diff --git a/README.md b/README.md
index 2a16c77..5b5003f 100644
--- a/README.md
+++ b/README.md
@@ -7,14 +7,34 @@
| OS | Артефакты | UI |
|----|----------|----|
| Windows amd64 | `Navis.exe` | GUI (WebView2) |
-| macOS arm64 | `Navis` · **`Navis.dmg`** · `Navis.app.zip` | CLI / .app |
-| macOS amd64 | `Navis` · **`Navis.dmg`** · `Navis.app.zip` | CLI / .app |
+| macOS universal | `Navis.dmg` · `Navis.app.zip` | CLI / .app — **рекомендуется** |
+| macOS arm64 | `Navis` · `Navis.dmg` · `Navis.app.zip` | CLI / .app |
+| macOS amd64 | `Navis` · `Navis.dmg` · `Navis.app.zip` | CLI / .app |
## Скачать macOS прямо с git
Репозиторий: https://git.evilfox.cc/test2/navi
-### 1. Узнайте архитектуру Mac
+### Быстрая установка (автовыбор архитектуры)
+
+```bash
+curl -fsSL "https://git.evilfox.cc/test2/navi/raw/branch/main/scripts/install-macos.sh" | bash
+```
+
+Скрипт скачает **универсальный DMG** (работает на Intel и Apple Silicon) и откроет его.
+
+### Универсальный DMG (рекомендуется)
+
+Подходит для **всех** Mac — M1/M2/M3/M4 и Intel:
+
+```bash
+cd ~/Downloads
+curl -fL -o Navis.dmg \
+ "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg"
+open Navis.dmg
+```
+
+### 1. Узнайте архитектуру Mac (если нужна отдельная сборка)
В Терминале:
@@ -25,7 +45,9 @@ uname -m
- `arm64` → Apple Silicon (M1/M2/M3/M4) → папка **darwin-arm64**
- `x86_64` → Intel → папка **darwin-amd64**
-### 2a. Скачать DMG (удобнее)
+> **Важно:** на Mac M4 нельзя ставить сборку из `darwin-amd64` — иконка будет с перечёркиванием. Используйте **darwin-universal** или **darwin-arm64**.
+
+### 2a. Скачать DMG для конкретной архитектуры
**Apple Silicon:**
@@ -153,6 +175,7 @@ cd ~/Navis
| Архитектура | CLI | DMG | ZIP (.app) |
|-------------|-----|-----|------------|
+| **universal** | [Navis](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis) | [Navis.dmg](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg) | [Navis.app.zip](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.app.zip) |
| arm64 | [Navis](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis) | [Navis.dmg](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg) | [Navis.app.zip](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip) |
| amd64 | [Navis](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis) | [Navis.dmg](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg) | [Navis.app.zip](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip) |
| манифест | [update.json](https://git.evilfox.cc/test2/navi/raw/branch/main/dist/update.json) | | |
@@ -210,6 +233,9 @@ https://evilfox.win/
Некоторые AV (Bkav, Microsoft Wacapew/Wacatac, Ikarus Trojan.WinGo.Agent, Google, Trapmine) часто помечают **любые** неподписанные Go-бинарники с сетью и сменой системного прокси.
+В 2.2.1:
+- универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре.
+
В 2.2.0:
- компактный список нод с пингом (как в Happ);
- параллельный пинг, кнопка «Лучший», автоподключение к серверу с минимальной задержкой после подписки.
diff --git a/build-macos.bat b/build-macos.bat
index 37ba0d6..c1b6069 100644
--- a/build-macos.bat
+++ b/build-macos.bat
@@ -4,6 +4,7 @@ cd /d "%~dp0"
mkdir "dist\navis-release\darwin-arm64" 2>nul
mkdir "dist\navis-release\darwin-amd64" 2>nul
+mkdir "dist\navis-release\darwin-universal" 2>nul
set CGO_ENABLED=0
set GOOS=darwin
@@ -19,15 +20,23 @@ set GOOS=
set GOARCH=
set CGO_ENABLED=
+go build -o "tools\mklipo\mklipo.exe" .\tools\mklipo
+if errorlevel 1 exit /b 1
+tools\mklipo\mklipo.exe "dist\navis-release\darwin-amd64\Navis" "dist\navis-release\darwin-arm64\Navis" "dist\navis-release\darwin-universal\Navis"
+if errorlevel 1 exit /b 1
+
go build -o "tools\packmac\packmac.exe" .\tools\packmac
if errorlevel 1 exit /b 1
-tools\packmac\packmac.exe -bin "dist\navis-release\darwin-arm64\Navis" -out "dist\navis-release\darwin-arm64" -version 2.2.0 -arch arm64
+tools\packmac\packmac.exe -bin "dist\navis-release\darwin-arm64\Navis" -out "dist\navis-release\darwin-arm64" -version 2.2.1 -arch arm64
if errorlevel 1 exit /b 1
-tools\packmac\packmac.exe -bin "dist\navis-release\darwin-amd64\Navis" -out "dist\navis-release\darwin-amd64" -version 2.2.0 -arch amd64
+tools\packmac\packmac.exe -bin "dist\navis-release\darwin-amd64\Navis" -out "dist\navis-release\darwin-amd64" -version 2.2.1 -arch amd64
+if errorlevel 1 exit /b 1
+tools\packmac\packmac.exe -bin "dist\navis-release\darwin-universal\Navis" -out "dist\navis-release\darwin-universal" -version 2.2.1 -arch universal
if errorlevel 1 exit /b 1
echo Built:
+dir "dist\navis-release\darwin-universal"
dir "dist\navis-release\darwin-arm64"
dir "dist\navis-release\darwin-amd64"
endlocal
diff --git a/dist/navis-release/Navis.exe b/dist/navis-release/Navis.exe
index 7c13344..e7a994b 100644
Binary files a/dist/navis-release/Navis.exe and b/dist/navis-release/Navis.exe differ
diff --git a/dist/navis-release/darwin-amd64/Navis b/dist/navis-release/darwin-amd64/Navis
index 905635d..3806f77 100644
Binary files a/dist/navis-release/darwin-amd64/Navis and b/dist/navis-release/darwin-amd64/Navis differ
diff --git a/dist/navis-release/darwin-amd64/Navis.app.zip b/dist/navis-release/darwin-amd64/Navis.app.zip
index f9371e0..1c03fc7 100644
Binary files a/dist/navis-release/darwin-amd64/Navis.app.zip and b/dist/navis-release/darwin-amd64/Navis.app.zip differ
diff --git a/dist/navis-release/darwin-amd64/Navis.dmg b/dist/navis-release/darwin-amd64/Navis.dmg
index 5315be5..90fb6ac 100644
Binary files a/dist/navis-release/darwin-amd64/Navis.dmg and b/dist/navis-release/darwin-amd64/Navis.dmg differ
diff --git a/dist/navis-release/darwin-arm64/Navis b/dist/navis-release/darwin-arm64/Navis
index b88bbc3..8a36804 100644
Binary files a/dist/navis-release/darwin-arm64/Navis and b/dist/navis-release/darwin-arm64/Navis differ
diff --git a/dist/navis-release/darwin-arm64/Navis.app.zip b/dist/navis-release/darwin-arm64/Navis.app.zip
index 9d0cdb5..4708563 100644
Binary files a/dist/navis-release/darwin-arm64/Navis.app.zip and b/dist/navis-release/darwin-arm64/Navis.app.zip differ
diff --git a/dist/navis-release/darwin-arm64/Navis.dmg b/dist/navis-release/darwin-arm64/Navis.dmg
index 90779f5..c71b32e 100644
Binary files a/dist/navis-release/darwin-arm64/Navis.dmg and b/dist/navis-release/darwin-arm64/Navis.dmg differ
diff --git a/dist/navis-release/darwin-universal/Navis b/dist/navis-release/darwin-universal/Navis
new file mode 100644
index 0000000..b4ad106
Binary files /dev/null and b/dist/navis-release/darwin-universal/Navis differ
diff --git a/dist/navis-release/darwin-universal/Navis.app.zip b/dist/navis-release/darwin-universal/Navis.app.zip
new file mode 100644
index 0000000..2dc7608
Binary files /dev/null and b/dist/navis-release/darwin-universal/Navis.app.zip differ
diff --git a/dist/navis-release/darwin-universal/Navis.dmg b/dist/navis-release/darwin-universal/Navis.dmg
new file mode 100644
index 0000000..d18157d
Binary files /dev/null and b/dist/navis-release/darwin-universal/Navis.dmg differ
diff --git a/dist/navis-release/update.json b/dist/navis-release/update.json
index 05df1b6..e258e40 100644
--- a/dist/navis-release/update.json
+++ b/dist/navis-release/update.json
@@ -1,30 +1,42 @@
{
- "version": "2.2.0",
- "notes": "Компактный список нод с пингом (как Happ), автовыбор и подключение к серверу с лучшим пингом",
+ "version": "2.2.1",
+ "notes": "Универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
- "sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3",
+ "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
- "sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3",
+ "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
- "sha256": "777564f1605209deb67b440a8f94667443498df38cef0a34a0ab8ab9922dab44",
+ "sha256": "b1589bffebb7cbeee17ca5a40cedb6ca614a3580be22488505a1403e1021c2b6",
"os": "darwin",
- "arch": "arm64"
+ "arch": "arm64",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
- "sha256": "5d0b0e3a2edebdb26f78eb39a7a67c6d7d7fb46beaa737869a0fec1150da3935",
+ "sha256": "149258fbad816aa2e73384da492bc91e3bf6700d4d01d55c9f35a3f68998232c",
"os": "darwin",
- "arch": "amd64"
+ "arch": "amd64",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip"
+ },
+ "darwin-universal": {
+ "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis",
+ "sha256": "37ceb0e47cd542dadcd406cedecc760d9aa71a40f0b109f81d560de3a4eba79",
+ "os": "darwin",
+ "arch": "universal",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.app.zip"
}
}
}
diff --git a/dist/update.json b/dist/update.json
index 05df1b6..e258e40 100644
--- a/dist/update.json
+++ b/dist/update.json
@@ -1,30 +1,42 @@
{
- "version": "2.2.0",
- "notes": "Компактный список нод с пингом (как Happ), автовыбор и подключение к серверу с лучшим пингом",
+ "version": "2.2.1",
+ "notes": "Универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
- "sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3",
+ "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
- "sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3",
+ "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
- "sha256": "777564f1605209deb67b440a8f94667443498df38cef0a34a0ab8ab9922dab44",
+ "sha256": "b1589bffebb7cbeee17ca5a40cedb6ca614a3580be22488505a1403e1021c2b6",
"os": "darwin",
- "arch": "arm64"
+ "arch": "arm64",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
- "sha256": "5d0b0e3a2edebdb26f78eb39a7a67c6d7d7fb46beaa737869a0fec1150da3935",
+ "sha256": "149258fbad816aa2e73384da492bc91e3bf6700d4d01d55c9f35a3f68998232c",
"os": "darwin",
- "arch": "amd64"
+ "arch": "amd64",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip"
+ },
+ "darwin-universal": {
+ "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis",
+ "sha256": "37ceb0e47cd542dadcd406cedecc760d9aa71a40f0b109f81d560de3a4eba79",
+ "os": "darwin",
+ "arch": "universal",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.app.zip"
}
}
}
diff --git a/internal/appui/index.html b/internal/appui/index.html
index 9d47ad5..3f55ffc 100644
--- a/internal/appui/index.html
+++ b/internal/appui/index.html
@@ -725,7 +725,7 @@
Navis
- 2.2
+ 2.2.1
Быстрый клиент · Naive · Hy2 · AWG · Xray
diff --git a/internal/update/update.go b/internal/update/update.go
index a86f42a..d6a7bdf 100644
--- a/internal/update/update.go
+++ b/internal/update/update.go
@@ -17,7 +17,7 @@ import (
)
// CurrentVersion is the shipped client version.
-const CurrentVersion = "2.2.0"
+const CurrentVersion = "2.2.1"
// DefaultManifestURL is the update feed (hosted in the project git repo).
const DefaultManifestURL = "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/update.json"
diff --git a/scripts/install-macos.sh b/scripts/install-macos.sh
new file mode 100644
index 0000000..dd1d7a4
--- /dev/null
+++ b/scripts/install-macos.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+set -euo pipefail
+
+BASE="https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release"
+ARCH="$(uname -m)"
+
+case "$ARCH" in
+ arm64)
+ SUBDIR="darwin-arm64"
+ ;;
+ x86_64)
+ SUBDIR="darwin-amd64"
+ ;;
+ *)
+ echo "Неподдерживаемая архитектура: $ARCH" >&2
+ exit 1
+ ;;
+esac
+
+DEST="${1:-$HOME/Downloads/Navis.dmg}"
+UNIVERSAL="$BASE/darwin-universal/Navis.dmg"
+SPECIFIC="$BASE/$SUBDIR/Navis.dmg"
+
+echo "Mac: $ARCH"
+echo "Рекомендуется универсальный DMG (Intel + Apple Silicon)…"
+if curl -fL -o "$DEST" "$UNIVERSAL"; then
+ echo "Скачан: $DEST"
+else
+ echo "Универсальный DMG недоступен, скачиваю $SUBDIR…"
+ curl -fL -o "$DEST" "$SPECIFIC"
+fi
+
+open "$DEST"
+echo "Откройте диск и перетащите Navis.app в Программы."
diff --git a/server/README.md b/server/README.md
index 6066eac..21a66f3 100644
--- a/server/README.md
+++ b/server/README.md
@@ -6,6 +6,7 @@
- Windows: `…/dist/navis-release/Navis.exe`
- macOS arm64: `…/dist/navis-release/darwin-arm64/Navis`
- macOS amd64: `…/dist/navis-release/darwin-amd64/Navis`
+- macOS universal (рекомендуется): `…/dist/navis-release/darwin-universal/Navis.dmg`
Пример `dist/update.json` (multi-platform + legacy url для старых клиентов):
diff --git a/server/update.json b/server/update.json
index 05df1b6..e258e40 100644
--- a/server/update.json
+++ b/server/update.json
@@ -1,30 +1,42 @@
{
- "version": "2.2.0",
- "notes": "Компактный список нод с пингом (как Happ), автовыбор и подключение к серверу с лучшим пингом",
+ "version": "2.2.1",
+ "notes": "Универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
- "sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3",
+ "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
- "sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3",
+ "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
- "sha256": "777564f1605209deb67b440a8f94667443498df38cef0a34a0ab8ab9922dab44",
+ "sha256": "b1589bffebb7cbeee17ca5a40cedb6ca614a3580be22488505a1403e1021c2b6",
"os": "darwin",
- "arch": "arm64"
+ "arch": "arm64",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
- "sha256": "5d0b0e3a2edebdb26f78eb39a7a67c6d7d7fb46beaa737869a0fec1150da3935",
+ "sha256": "149258fbad816aa2e73384da492bc91e3bf6700d4d01d55c9f35a3f68998232c",
"os": "darwin",
- "arch": "amd64"
+ "arch": "amd64",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip"
+ },
+ "darwin-universal": {
+ "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis",
+ "sha256": "37ceb0e47cd542dadcd406cedecc760d9aa71a40f0b109f81d560de3a4eba79",
+ "os": "darwin",
+ "arch": "universal",
+ "dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg",
+ "zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.app.zip"
}
}
}
diff --git a/tools/mklipo/main.go b/tools/mklipo/main.go
new file mode 100644
index 0000000..bdd09d3
--- /dev/null
+++ b/tools/mklipo/main.go
@@ -0,0 +1,105 @@
+// mklipo merges two Mach-O binaries into one macOS universal (fat) binary.
+package main
+
+import (
+ "encoding/binary"
+ "fmt"
+ "os"
+)
+
+const (
+ fatMagic = 0xCAFEBABE
+ cpuTypeX86_64 = 0x01000007
+ cpuTypeARM64 = 0x0100000c
+ fatArchSize = 20
+)
+
+type slice struct {
+ cpu, sub uint32
+ data []byte
+}
+
+func main() {
+ if len(os.Args) != 4 {
+ fmt.Fprintln(os.Stderr, "usage: mklipo ")
+ os.Exit(2)
+ }
+ amd, err := os.ReadFile(os.Args[1])
+ if err != nil {
+ fatal(err)
+ }
+ arm, err := os.ReadFile(os.Args[2])
+ if err != nil {
+ fatal(err)
+ }
+ if err := writeFat(os.Args[3], []slice{
+ {cpuTypeX86_64, 3, amd},
+ {cpuTypeARM64, 0, arm},
+ }); err != nil {
+ fatal(err)
+ }
+}
+
+func writeFat(path string, parts []slice) error {
+ const align uint32 = 0x4000
+ hdr := 8 + fatArchSize*len(parts)
+ offsets := make([]uint32, len(parts))
+ cur := uint32(hdr)
+ for i, p := range parts {
+ pad := (align - (cur % align)) % align
+ cur += pad
+ offsets[i] = cur
+ cur += uint32(len(p.data))
+ }
+
+ out, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o755)
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+
+ if err := binary.Write(out, binary.BigEndian, uint32(fatMagic)); err != nil {
+ return err
+ }
+ if err := binary.Write(out, binary.BigEndian, uint32(len(parts))); err != nil {
+ return err
+ }
+ for i, p := range parts {
+ if err := binary.Write(out, binary.BigEndian, p.cpu); err != nil {
+ return err
+ }
+ if err := binary.Write(out, binary.BigEndian, p.sub); err != nil {
+ return err
+ }
+ if err := binary.Write(out, binary.BigEndian, offsets[i]); err != nil {
+ return err
+ }
+ if err := binary.Write(out, binary.BigEndian, uint32(len(p.data))); err != nil {
+ return err
+ }
+ if err := binary.Write(out, binary.BigEndian, align); err != nil {
+ return err
+ }
+ }
+
+ cur = uint32(hdr)
+ for _, p := range parts {
+ pad := (align - (cur % align)) % align
+ if pad > 0 {
+ if _, err := out.Write(make([]byte, pad)); err != nil {
+ return err
+ }
+ cur += pad
+ }
+ if _, err := out.Write(p.data); err != nil {
+ return err
+ }
+ cur += uint32(len(p.data))
+ }
+ return nil
+}
+
+func fatal(err error) {
+ fmt.Fprintln(os.Stderr, "mklipo:", err)
+ os.Exit(1)
+}
diff --git a/tools/packmac/main.go b/tools/packmac/main.go
index df5bd20..87d0fdd 100644
--- a/tools/packmac/main.go
+++ b/tools/packmac/main.go
@@ -42,33 +42,49 @@ func run(binPath, outDir, version, arch string) error {
defer os.RemoveAll(stage)
appRoot := filepath.Join(stage, "Navis.app")
- if err := writeAppBundle(appRoot, binPath, version); err != nil {
+ if err := writeAppBundle(appRoot, binPath, version, arch); err != nil {
return err
}
readme := filepath.Join(stage, "README.txt")
if err := os.WriteFile(readme, []byte(readmeText(version, arch)), 0o644); err != nil {
return err
}
+ warnName := archWarningFilename(arch)
+ if warnName != "" {
+ if err := os.WriteFile(filepath.Join(stage, warnName), []byte(archWarningText(arch)), 0o644); err != nil {
+ return err
+ }
+ }
+ zipEntries := []string{"Navis.app", "README.txt"}
+ if warnName != "" {
+ zipEntries = append(zipEntries, warnName)
+ }
zipPath := filepath.Join(outDir, "Navis.app.zip")
- if err := zipDir(zipPath, stage, []string{"Navis.app", "README.txt"}); err != nil {
+ if err := zipDir(zipPath, stage, zipEntries); err != nil {
return fmt.Errorf("zip: %w", err)
}
fmt.Println("wrote", zipPath)
dmgPath := filepath.Join(outDir, "Navis.dmg")
- if err := writeDMG(dmgPath, appRoot, readme, "Navis-"+arch); err != nil {
+ dmgFiles := []dmgEntry{{appRoot, "/Navis.app"}}
+ if warnName != "" {
+ dmgFiles = append(dmgFiles, dmgEntry{filepath.Join(stage, warnName), "/" + warnName})
+ }
+ dmgFiles = append(dmgFiles, dmgEntry{readme, "/README.txt"})
+ if err := writeDMG(dmgPath, dmgFiles, "Navis-"+arch); err != nil {
return fmt.Errorf("dmg: %w", err)
}
fmt.Println("wrote", dmgPath)
return nil
}
-func writeAppBundle(appRoot, binPath, version string) error {
+func writeAppBundle(appRoot, binPath, version, arch string) error {
macOSDir := filepath.Join(appRoot, "Contents", "MacOS")
if err := os.MkdirAll(macOSDir, 0o755); err != nil {
return err
}
+ archPriority := architecturePriorityXML(arch)
plist := fmt.Sprintf(`
@@ -80,10 +96,10 @@ func writeAppBundle(appRoot, binPath, version string) error {
CFBundleShortVersionString%s
CFBundleVersion%s
LSMinimumSystemVersion11.0
- CFBundleInfoDictionaryVersion6.0
+ CFBundleInfoDictionaryVersion6.0%s
-`, version, version)
+`, version, version, archPriority)
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil {
return err
}
@@ -94,21 +110,25 @@ func writeAppBundle(appRoot, binPath, version string) error {
return nil
}
-func writeDMG(dmgPath, appRoot, readmePath, volume string) error {
+type dmgEntry struct {
+ srcPath string
+ dstPath string
+}
+
+func writeDMG(dmgPath string, files []dmgEntry, volume string) error {
_ = os.Remove(dmgPath)
- appSize, err := dirSize(appRoot)
- if err != nil {
- return err
+ var need int64
+ for _, f := range files {
+ if fi, err := os.Stat(f.srcPath); err == nil && !fi.IsDir() {
+ need += fi.Size()
+ } else if sz, err := dirSize(f.srcPath); err == nil {
+ need += sz
+ }
}
- readmeSize, err := fileSize(readmePath)
- if err != nil {
- return err
- }
- need := appSize + readmeSize + 4*1024*1024
+ need += 4 * 1024 * 1024
if need < 12*1024*1024 {
need = 12 * 1024 * 1024
}
- // round up to 2048
need = ((need + 2047) / 2048) * 2048
mydisk, err := diskfs.Create(dmgPath, need, diskfs.SectorSizeDefault)
@@ -125,13 +145,23 @@ func writeDMG(dmgPath, appRoot, readmePath, volume string) error {
return err
}
- if err := copyTreeToISO(fs, appRoot, "/Navis.app"); err != nil {
- _ = fs.Close()
- return err
- }
- if err := writeISOFile(fs, "/README.txt", readmePath, 0o644); err != nil {
- _ = fs.Close()
- return err
+ for _, f := range files {
+ info, err := os.Stat(f.srcPath)
+ if err != nil {
+ _ = fs.Close()
+ return err
+ }
+ if info.IsDir() {
+ if err := copyTreeToISO(fs, f.srcPath, f.dstPath); err != nil {
+ _ = fs.Close()
+ return err
+ }
+ continue
+ }
+ if err := writeISOFile(fs, f.dstPath, f.srcPath, 0o644); err != nil {
+ _ = fs.Close()
+ return err
+ }
}
iso, ok := fs.(*iso9660.FileSystem)
@@ -336,19 +366,114 @@ func sanitizeVol(s string) string {
}
func readmeText(version, arch string) string {
- return fmt.Sprintf(`Navis %s for macOS (%s)
+ switch arch {
+ case "universal":
+ return fmt.Sprintf(`Navis %s for macOS (универсальная сборка)
-1) Open this disk image
-2) Drag Navis.app to Applications (or any folder)
-3) First launch may need:
+Подходит для Apple Silicon (M1/M2/M3/M4) и Intel Mac.
+
+1) Перетащите Navis.app в Программы (Applications)
+2) При первом запуске, если macOS блокирует:
xattr -dr com.apple.quarantine /Applications/Navis.app
-4) Run from Terminal:
+3) В Терминале:
/Applications/Navis.app/Contents/MacOS/Navis init
/Applications/Navis.app/Contents/MacOS/Navis install-core
/Applications/Navis.app/Contents/MacOS/Navis connect
-Or use the CLI binary next to this DMG on git (file named Navis).
+Магазин: https://evilfox.win/
+`, version)
+ case "arm64":
+ return fmt.Sprintf(`Navis %s for macOS (Apple Silicon: M1/M2/M3/M4)
-Shop: https://evilfox.win/
+⚠️ Только для Mac с чипом Apple Silicon (arm64).
+На Intel Mac скачайте darwin-amd64 или darwin-universal.
+
+1) Перетащите Navis.app в Программы
+2) xattr -dr com.apple.quarantine /Applications/Navis.app
+3) /Applications/Navis.app/Contents/MacOS/Navis connect
+
+Магазин: https://evilfox.win/
+`, version)
+ case "amd64":
+ return fmt.Sprintf(`Navis %s for macOS (Intel x86_64)
+
+⚠️ Только для Intel Mac.
+На Mac M1/M2/M3/M4 эта сборка НЕ запустится — скачайте darwin-arm64 или darwin-universal.
+
+1) Перетащите Navis.app в Программы
+2) xattr -dr com.apple.quarantine /Applications/Navis.app
+3) /Applications/Navis.app/Contents/MacOS/Navis connect
+
+Магазин: https://evilfox.win/
+`, version)
+ default:
+ return fmt.Sprintf(`Navis %s for macOS (%s)
+
+1) Drag Navis.app to Applications
+2) xattr -dr com.apple.quarantine /Applications/Navis.app
+3) /Applications/Navis.app/Contents/MacOS/Navis connect
`, version, arch)
+ }
+}
+
+func archWarningFilename(arch string) string {
+ switch arch {
+ case "amd64":
+ return "ТОЛЬКО-INTEL-MAC.txt"
+ case "arm64":
+ return "ТОЛЬКО-APPLE-SILICON.txt"
+ default:
+ return ""
+ }
+}
+
+func archWarningText(arch string) string {
+ switch arch {
+ case "amd64":
+ return `ВНИМАНИЕ
+
+Эта сборка Navis только для Intel Mac (x86_64).
+
+Если у вас Mac mini / MacBook с чипом M1, M2, M3 или M4 —
+закройте этот диск и скачайте универсальный DMG:
+
+https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg
+
+Или arm64:
+https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg
+`
+ case "arm64":
+ return `ВНИМАНИЕ
+
+Эта сборка Navis только для Apple Silicon (M1/M2/M3/M4).
+
+Если у вас Intel Mac — скачайте darwin-amd64 или универсальный DMG:
+
+https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg
+`
+ default:
+ return ""
+ }
+}
+
+func architecturePriorityXML(arch string) string {
+ switch arch {
+ case "universal":
+ return `
+ LSArchitecturePriority
+
+ arm64
+ x86_64
+ `
+ case "arm64":
+ return `
+ LSArchitecturePriority
+ arm64`
+ case "amd64":
+ return `
+ LSArchitecturePriority
+ x86_64`
+ default:
+ return ""
+ }
}
diff --git a/versioninfo.json b/versioninfo.json
index 9ea57a9..b07185d 100644
--- a/versioninfo.json
+++ b/versioninfo.json
@@ -1,7 +1,7 @@
{
"FixedFileInfo": {
- "FileVersion": { "Major": 2, "Minor": 2, "Patch": 0, "Build": 0 },
- "ProductVersion": { "Major": 2, "Minor": 2, "Patch": 0, "Build": 0 },
+ "FileVersion": { "Major": 2, "Minor": 2, "Patch": 1, "Build": 0 },
+ "ProductVersion": { "Major": 2, "Minor": 2, "Patch": 1, "Build": 0 },
"FileFlagsMask": "3f",
"FileFlags": "00",
"FileOS": "40004",
@@ -11,12 +11,12 @@
"StringFileInfo": {
"CompanyName": "EvilFox",
"FileDescription": "Navis 2 — VPN client (Naive / Hy2 / AWG / VLESS / VMess / Trojan)",
- "FileVersion": "2.2.0.0",
+ "FileVersion": "2.2.1.0",
"InternalName": "Navis",
"LegalCopyright": "Copyright (c) EvilFox",
"OriginalFilename": "Navis.exe",
"ProductName": "Navis",
- "ProductVersion": "2.2.0.0",
+ "ProductVersion": "2.2.1.0",
"Comments": "Open-source VPN/proxy client. https://evilfox.win/"
},
"VarFileInfo": {