Release 2.2.1: universal macOS DMG and arch install fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-07-29 10:36:24 +03:00
co-authored by Cursor
parent 8c513f6e08
commit a2cdad5ebe
22 changed files with 402 additions and 66 deletions
+30 -4
View File
@@ -7,14 +7,34 @@
| OS | Артефакты | UI | | OS | Артефакты | UI |
|----|----------|----| |----|----------|----|
| Windows amd64 | `Navis.exe` | GUI (WebView2) | | Windows amd64 | `Navis.exe` | GUI (WebView2) |
| macOS arm64 | `Navis` · **`Navis.dmg`** · `Navis.app.zip` | CLI / .app | | macOS universal | `Navis.dmg` · `Navis.app.zip` | CLI / .app**рекомендуется** |
| macOS amd64 | `Navis` · **`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 ## Скачать macOS прямо с git
Репозиторий: https://git.evilfox.cc/test2/navi Репозиторий: 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** - `arm64` → Apple Silicon (M1/M2/M3/M4) → папка **darwin-arm64**
- `x86_64` → Intel → папка **darwin-amd64** - `x86_64` → Intel → папка **darwin-amd64**
### 2a. Скачать DMG (удобнее) > **Важно:** на Mac M4 нельзя ставить сборку из `darwin-amd64` — иконка будет с перечёркиванием. Используйте **darwin-universal** или **darwin-arm64**.
### 2a. Скачать DMG для конкретной архитектуры
**Apple Silicon:** **Apple Silicon:**
@@ -153,6 +175,7 @@ cd ~/Navis
| Архитектура | CLI | DMG | ZIP (.app) | | Архитектура | 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) | | 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) | | 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) | | | | манифест | [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-бинарники с сетью и сменой системного прокси. Некоторые AV (Bkav, Microsoft Wacapew/Wacatac, Ikarus Trojan.WinGo.Agent, Google, Trapmine) часто помечают **любые** неподписанные Go-бинарники с сетью и сменой системного прокси.
В 2.2.1:
- универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре.
В 2.2.0: В 2.2.0:
- компактный список нод с пингом (как в Happ); - компактный список нод с пингом (как в Happ);
- параллельный пинг, кнопка «Лучший», автоподключение к серверу с минимальной задержкой после подписки. - параллельный пинг, кнопка «Лучший», автоподключение к серверу с минимальной задержкой после подписки.
+11 -2
View File
@@ -4,6 +4,7 @@ cd /d "%~dp0"
mkdir "dist\navis-release\darwin-arm64" 2>nul mkdir "dist\navis-release\darwin-arm64" 2>nul
mkdir "dist\navis-release\darwin-amd64" 2>nul mkdir "dist\navis-release\darwin-amd64" 2>nul
mkdir "dist\navis-release\darwin-universal" 2>nul
set CGO_ENABLED=0 set CGO_ENABLED=0
set GOOS=darwin set GOOS=darwin
@@ -19,15 +20,23 @@ set GOOS=
set GOARCH= set GOARCH=
set CGO_ENABLED= 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 go build -o "tools\packmac\packmac.exe" .\tools\packmac
if errorlevel 1 exit /b 1 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 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 if errorlevel 1 exit /b 1
echo Built: echo Built:
dir "dist\navis-release\darwin-universal"
dir "dist\navis-release\darwin-arm64" dir "dist\navis-release\darwin-arm64"
dir "dist\navis-release\darwin-amd64" dir "dist\navis-release\darwin-amd64"
endlocal endlocal
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+20 -8
View File
@@ -1,30 +1,42 @@
{ {
"version": "2.2.0", "version": "2.2.1",
"notes": "Компактный список нод с пингом (как Happ), автовыбор и подключение к серверу с лучшим пингом", "notes": "Универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре",
"platform": "windows-amd64", "platform": "windows-amd64",
"os": "windows", "os": "windows",
"arch": "amd64", "arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3", "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"mandatory": false, "mandatory": false,
"platforms": { "platforms": {
"windows-amd64": { "windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3", "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"os": "windows", "os": "windows",
"arch": "amd64" "arch": "amd64"
}, },
"darwin-arm64": { "darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "777564f1605209deb67b440a8f94667443498df38cef0a34a0ab8ab9922dab44", "sha256": "b1589bffebb7cbeee17ca5a40cedb6ca614a3580be22488505a1403e1021c2b6",
"os": "darwin", "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": { "darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "5d0b0e3a2edebdb26f78eb39a7a67c6d7d7fb46beaa737869a0fec1150da3935", "sha256": "149258fbad816aa2e73384da492bc91e3bf6700d4d01d55c9f35a3f68998232c",
"os": "darwin", "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"
} }
} }
} }
+20 -8
View File
@@ -1,30 +1,42 @@
{ {
"version": "2.2.0", "version": "2.2.1",
"notes": "Компактный список нод с пингом (как Happ), автовыбор и подключение к серверу с лучшим пингом", "notes": "Универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре",
"platform": "windows-amd64", "platform": "windows-amd64",
"os": "windows", "os": "windows",
"arch": "amd64", "arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3", "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"mandatory": false, "mandatory": false,
"platforms": { "platforms": {
"windows-amd64": { "windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3", "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"os": "windows", "os": "windows",
"arch": "amd64" "arch": "amd64"
}, },
"darwin-arm64": { "darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "777564f1605209deb67b440a8f94667443498df38cef0a34a0ab8ab9922dab44", "sha256": "b1589bffebb7cbeee17ca5a40cedb6ca614a3580be22488505a1403e1021c2b6",
"os": "darwin", "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": { "darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "5d0b0e3a2edebdb26f78eb39a7a67c6d7d7fb46beaa737869a0fec1150da3935", "sha256": "149258fbad816aa2e73384da492bc91e3bf6700d4d01d55c9f35a3f68998232c",
"os": "darwin", "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"
} }
} }
} }
+1 -1
View File
@@ -725,7 +725,7 @@
<div class="brand-wrap"> <div class="brand-wrap">
<div class="brand-row"> <div class="brand-row">
<h1 class="brand">Navis</h1> <h1 class="brand">Navis</h1>
<span class="badge-ver">2.2</span> <span class="badge-ver">2.2.1</span>
</div> </div>
<p class="tagline">Быстрый клиент · Naive · Hy2 · AWG · Xray</p> <p class="tagline">Быстрый клиент · Naive · Hy2 · AWG · Xray</p>
</div> </div>
+1 -1
View File
@@ -17,7 +17,7 @@ import (
) )
// CurrentVersion is the shipped client version. // 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). // 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" const DefaultManifestURL = "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/update.json"
+34
View File
@@ -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 в Программы."
+1
View File
@@ -6,6 +6,7 @@
- Windows: `…/dist/navis-release/Navis.exe` - Windows: `…/dist/navis-release/Navis.exe`
- macOS arm64: `…/dist/navis-release/darwin-arm64/Navis` - macOS arm64: `…/dist/navis-release/darwin-arm64/Navis`
- macOS amd64: `…/dist/navis-release/darwin-amd64/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 для старых клиентов): Пример `dist/update.json` (multi-platform + legacy url для старых клиентов):
+20 -8
View File
@@ -1,30 +1,42 @@
{ {
"version": "2.2.0", "version": "2.2.1",
"notes": "Компактный список нод с пингом (как Happ), автовыбор и подключение к серверу с лучшим пингом", "notes": "Универсальный macOS DMG (Intel + Apple Silicon), скрипт автоустановки, предупреждения при неверной архитектуре",
"platform": "windows-amd64", "platform": "windows-amd64",
"os": "windows", "os": "windows",
"arch": "amd64", "arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3", "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"mandatory": false, "mandatory": false,
"platforms": { "platforms": {
"windows-amd64": { "windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "acd3a57cb52d745ecd0dc24074cfbd0299820d863ce00c2d4ce7753fb7dc73f3", "sha256": "993e17d6390c8a4378e51016012006f18db1f6bd7c25957a4bf82fe31ab63473",
"os": "windows", "os": "windows",
"arch": "amd64" "arch": "amd64"
}, },
"darwin-arm64": { "darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "777564f1605209deb67b440a8f94667443498df38cef0a34a0ab8ab9922dab44", "sha256": "b1589bffebb7cbeee17ca5a40cedb6ca614a3580be22488505a1403e1021c2b6",
"os": "darwin", "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": { "darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis", "url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "5d0b0e3a2edebdb26f78eb39a7a67c6d7d7fb46beaa737869a0fec1150da3935", "sha256": "149258fbad816aa2e73384da492bc91e3bf6700d4d01d55c9f35a3f68998232c",
"os": "darwin", "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"
} }
} }
} }
+105
View File
@@ -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 <amd64-bin> <arm64-bin> <out>")
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)
}
+155 -30
View File
@@ -42,33 +42,49 @@ func run(binPath, outDir, version, arch string) error {
defer os.RemoveAll(stage) defer os.RemoveAll(stage)
appRoot := filepath.Join(stage, "Navis.app") 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 return err
} }
readme := filepath.Join(stage, "README.txt") readme := filepath.Join(stage, "README.txt")
if err := os.WriteFile(readme, []byte(readmeText(version, arch)), 0o644); err != nil { if err := os.WriteFile(readme, []byte(readmeText(version, arch)), 0o644); err != nil {
return err 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") 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) return fmt.Errorf("zip: %w", err)
} }
fmt.Println("wrote", zipPath) fmt.Println("wrote", zipPath)
dmgPath := filepath.Join(outDir, "Navis.dmg") 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) return fmt.Errorf("dmg: %w", err)
} }
fmt.Println("wrote", dmgPath) fmt.Println("wrote", dmgPath)
return nil return nil
} }
func writeAppBundle(appRoot, binPath, version string) error { func writeAppBundle(appRoot, binPath, version, arch string) error {
macOSDir := filepath.Join(appRoot, "Contents", "MacOS") macOSDir := filepath.Join(appRoot, "Contents", "MacOS")
if err := os.MkdirAll(macOSDir, 0o755); err != nil { if err := os.MkdirAll(macOSDir, 0o755); err != nil {
return err return err
} }
archPriority := architecturePriorityXML(arch)
plist := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> plist := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@@ -80,10 +96,10 @@ func writeAppBundle(appRoot, binPath, version string) error {
<key>CFBundleShortVersionString</key><string>%s</string> <key>CFBundleShortVersionString</key><string>%s</string>
<key>CFBundleVersion</key><string>%s</string> <key>CFBundleVersion</key><string>%s</string>
<key>LSMinimumSystemVersion</key><string>11.0</string> <key>LSMinimumSystemVersion</key><string>11.0</string>
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string> <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>%s
</dict> </dict>
</plist> </plist>
`, version, version) `, version, version, archPriority)
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil { if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil {
return err return err
} }
@@ -94,21 +110,25 @@ func writeAppBundle(appRoot, binPath, version string) error {
return nil 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) _ = os.Remove(dmgPath)
appSize, err := dirSize(appRoot) var need int64
if err != nil { for _, f := range files {
return err 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) need += 4 * 1024 * 1024
if err != nil {
return err
}
need := appSize + readmeSize + 4*1024*1024
if need < 12*1024*1024 { if need < 12*1024*1024 {
need = 12 * 1024 * 1024 need = 12 * 1024 * 1024
} }
// round up to 2048
need = ((need + 2047) / 2048) * 2048 need = ((need + 2047) / 2048) * 2048
mydisk, err := diskfs.Create(dmgPath, need, diskfs.SectorSizeDefault) mydisk, err := diskfs.Create(dmgPath, need, diskfs.SectorSizeDefault)
@@ -125,13 +145,23 @@ func writeDMG(dmgPath, appRoot, readmePath, volume string) error {
return err return err
} }
if err := copyTreeToISO(fs, appRoot, "/Navis.app"); err != nil { for _, f := range files {
_ = fs.Close() info, err := os.Stat(f.srcPath)
return err if err != nil {
} _ = fs.Close()
if err := writeISOFile(fs, "/README.txt", readmePath, 0o644); err != nil { return err
_ = 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) iso, ok := fs.(*iso9660.FileSystem)
@@ -336,19 +366,114 @@ func sanitizeVol(s string) string {
} }
func readmeText(version, arch 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 Подходит для Apple Silicon (M1/M2/M3/M4) и Intel Mac.
2) Drag Navis.app to Applications (or any folder)
3) First launch may need: 1) Перетащите Navis.app в Программы (Applications)
2) При первом запуске, если macOS блокирует:
xattr -dr com.apple.quarantine /Applications/Navis.app 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 init
/Applications/Navis.app/Contents/MacOS/Navis install-core /Applications/Navis.app/Contents/MacOS/Navis install-core
/Applications/Navis.app/Contents/MacOS/Navis connect /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) `, 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 `
<key>LSArchitecturePriority</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>`
case "arm64":
return `
<key>LSArchitecturePriority</key>
<array><string>arm64</string></array>`
case "amd64":
return `
<key>LSArchitecturePriority</key>
<array><string>x86_64</string></array>`
default:
return ""
}
} }
+4 -4
View File
@@ -1,7 +1,7 @@
{ {
"FixedFileInfo": { "FixedFileInfo": {
"FileVersion": { "Major": 2, "Minor": 2, "Patch": 0, "Build": 0 }, "FileVersion": { "Major": 2, "Minor": 2, "Patch": 1, "Build": 0 },
"ProductVersion": { "Major": 2, "Minor": 2, "Patch": 0, "Build": 0 }, "ProductVersion": { "Major": 2, "Minor": 2, "Patch": 1, "Build": 0 },
"FileFlagsMask": "3f", "FileFlagsMask": "3f",
"FileFlags": "00", "FileFlags": "00",
"FileOS": "40004", "FileOS": "40004",
@@ -11,12 +11,12 @@
"StringFileInfo": { "StringFileInfo": {
"CompanyName": "EvilFox", "CompanyName": "EvilFox",
"FileDescription": "Navis 2 — VPN client (Naive / Hy2 / AWG / VLESS / VMess / Trojan)", "FileDescription": "Navis 2 — VPN client (Naive / Hy2 / AWG / VLESS / VMess / Trojan)",
"FileVersion": "2.2.0.0", "FileVersion": "2.2.1.0",
"InternalName": "Navis", "InternalName": "Navis",
"LegalCopyright": "Copyright (c) EvilFox", "LegalCopyright": "Copyright (c) EvilFox",
"OriginalFilename": "Navis.exe", "OriginalFilename": "Navis.exe",
"ProductName": "Navis", "ProductName": "Navis",
"ProductVersion": "2.2.0.0", "ProductVersion": "2.2.1.0",
"Comments": "Open-source VPN/proxy client. https://evilfox.win/" "Comments": "Open-source VPN/proxy client. https://evilfox.win/"
}, },
"VarFileInfo": { "VarFileInfo": {