Release 1.4.1: add macOS DMG and Navis.app.zip to release artifacts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-07-28 08:09:21 +03:00
co-authored by Cursor
parent 4c2d6b8be7
commit a1e9019dcd
18 changed files with 542 additions and 54 deletions
+62 -14
View File
@@ -4,11 +4,11 @@
## Платформы
| OS | Артефакт | UI |
| OS | Артефакты | UI |
|----|----------|----|
| Windows amd64 | `dist/navis-release/Navis.exe` | GUI (WebView2) |
| macOS arm64 | `dist/navis-release/darwin-arm64/Navis` | CLI |
| macOS amd64 | `dist/navis-release/darwin-amd64/Navis` | CLI |
| 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 прямо с git
@@ -25,7 +25,55 @@ uname -m
- `arm64` → Apple Silicon (M1/M2/M3/M4) → папка **darwin-arm64**
- `x86_64` → Intel → папка **darwin-amd64**
### 2. Скачайте бинарник одной командой
### 2a. Скачать DMG (удобнее)
**Apple Silicon:**
```bash
cd ~/Downloads
curl -fL -o Navis.dmg \
"https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg"
open Navis.dmg
```
**Intel:**
```bash
cd ~/Downloads
curl -fL -o Navis.dmg \
"https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg"
open Navis.dmg
```
Откроется диск с `Navis.app` — перетащите в **Программы** (Applications).
Если Gatekeeper ругается:
```bash
xattr -dr com.apple.quarantine /Applications/Navis.app
```
Запуск CLI из .app:
```bash
/Applications/Navis.app/Contents/MacOS/Navis init
/Applications/Navis.app/Contents/MacOS/Navis install-core
/Applications/Navis.app/Contents/MacOS/Navis connect
```
Альтернатива DMG — zip с тем же `.app`:
```bash
# arm64
curl -fL -o Navis.app.zip \
"https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip"
# amd64
curl -fL -o Navis.app.zip \
"https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip"
unzip Navis.app.zip
```
### 2b. Скачать CLI-бинарник одной командой
**Apple Silicon (arm64):**
@@ -51,7 +99,7 @@ chmod +x Navis
./Navis check-update
```
### 3. Первый запуск
### 3. Первый запуск (CLI)
```bash
cd ~/Navis
@@ -82,10 +130,10 @@ cd ~/Navis
“Navis” cannot be opened because it is from an unidentified developer
```
Снимите quarantine и разрешите в Настройках:
```bash
xattr -dr com.apple.quarantine ~/Navis/Navis
# или для .app:
xattr -dr com.apple.quarantine /Applications/Navis.app
```
Затем: **Системные настройки → Конфиденциальность и безопасность → Всё равно открыть**.
@@ -99,15 +147,15 @@ cd ~/Navis
# закройте процесс Navis — бинарник подменится сам
```
Или скачайте файл заново теми же `curl` из шага 2.
Или скачайте DMG/бинарник заново.
Прямые ссылки (raw):
| Архитектура | URL |
|-------------|-----|
| arm64 | https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis |
| amd64 | https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis |
| манифест | https://git.evilfox.cc/test2/navi/raw/branch/main/dist/update.json |
| Архитектура | CLI | DMG | ZIP (.app) |
|-------------|-----|-----|------------|
| 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) | | |
## Сборка Windows
+14 -2
View File
@@ -15,7 +15,19 @@ set GOARCH=amd64
go build -ldflags="-s -w" -o "dist\navis-release\darwin-amd64\Navis" .\cmd\vpnclient
if errorlevel 1 exit /b 1
set GOOS=
set GOARCH=
set CGO_ENABLED=
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 1.4.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 1.4.1 -arch amd64
if errorlevel 1 exit /b 1
echo Built:
dir /b "dist\navis-release\darwin-arm64\Navis"
dir /b "dist\navis-release\darwin-amd64\Navis"
dir "dist\navis-release\darwin-arm64"
dir "dist\navis-release\darwin-amd64"
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.
+16 -8
View File
@@ -1,30 +1,38 @@
{
"version": "1.4.0",
"notes": "macOS CLI (arm64/amd64), multi-platform updates, networksetup proxy, naive tar.xz",
"version": "1.4.1",
"notes": "macOS DMG + Navis.app.zip в релизе (arm64/amd64)",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "110ab8f5806f2635b39ec586d8218120d0041a82212715530ae8c3838078bf11",
"sha256": "4217542dfa49a60d522295267b9bd7f3a838b2917b68d9ee59041abecf149e09",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "110ab8f5806f2635b39ec586d8218120d0041a82212715530ae8c3838078bf11",
"sha256": "4217542dfa49a60d522295267b9bd7f3a838b2917b68d9ee59041abecf149e09",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "4ce2b429fe4c8e8e1fdf776150003e42e4452e9ecf95cb55a714f84884717fd6",
"sha256": "a3bc2bcc256842d3914c44385a5fb9b61e691be2c19a9c283bc2099fcc48af9a",
"os": "darwin",
"arch": "arm64"
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
"dmg_sha256": "a49584770e7453e7046ba80a4da8ac84a34797e3a8e4eb307a3d572d1fc95b59",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip",
"zip_sha256": "436c8c0382bf4491d288f6899d1a8fb0f7cd86b53063801f9dbc03f29a92046d"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "a91bc03c7c68d896c42bb3520010e96191c12a0e95e2b9c2582dd2732637d9af",
"sha256": "a1471b447e481e3fe61a65bb66c8633facd968087907e561584fd845842805fb",
"os": "darwin",
"arch": "amd64"
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
"dmg_sha256": "eca2127f956959c1a4567dece779bfcd4bd414d2f63f430c24b133456fa5c56a",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip",
"zip_sha256": "de039f591032dbcf69e81499074cf7f51b80c83f08958521df9b8f873d2fe7be"
}
}
}
+16 -8
View File
@@ -1,30 +1,38 @@
{
"version": "1.4.0",
"notes": "macOS CLI (arm64/amd64), multi-platform updates, networksetup proxy, naive tar.xz",
"version": "1.4.1",
"notes": "macOS DMG + Navis.app.zip в релизе (arm64/amd64)",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "110ab8f5806f2635b39ec586d8218120d0041a82212715530ae8c3838078bf11",
"sha256": "4217542dfa49a60d522295267b9bd7f3a838b2917b68d9ee59041abecf149e09",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "110ab8f5806f2635b39ec586d8218120d0041a82212715530ae8c3838078bf11",
"sha256": "4217542dfa49a60d522295267b9bd7f3a838b2917b68d9ee59041abecf149e09",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "4ce2b429fe4c8e8e1fdf776150003e42e4452e9ecf95cb55a714f84884717fd6",
"sha256": "a3bc2bcc256842d3914c44385a5fb9b61e691be2c19a9c283bc2099fcc48af9a",
"os": "darwin",
"arch": "arm64"
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
"dmg_sha256": "a49584770e7453e7046ba80a4da8ac84a34797e3a8e4eb307a3d572d1fc95b59",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip",
"zip_sha256": "436c8c0382bf4491d288f6899d1a8fb0f7cd86b53063801f9dbc03f29a92046d"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "a91bc03c7c68d896c42bb3520010e96191c12a0e95e2b9c2582dd2732637d9af",
"sha256": "a1471b447e481e3fe61a65bb66c8633facd968087907e561584fd845842805fb",
"os": "darwin",
"arch": "amd64"
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
"dmg_sha256": "eca2127f956959c1a4567dece779bfcd4bd414d2f63f430c24b133456fa5c56a",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip",
"zip_sha256": "de039f591032dbcf69e81499074cf7f51b80c83f08958521df9b8f873d2fe7be"
}
}
}
+14 -2
View File
@@ -3,9 +3,21 @@ module vpnclient
go 1.25.0
require (
github.com/diskfs/go-diskfs v1.9.4
github.com/jchv/go-webview2 v0.0.0-20260205173254-56598839c808
golang.org/x/image v0.44.0
golang.org/x/sys v0.33.0
golang.org/x/sys v0.43.0
)
require github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 // indirect
require (
github.com/anchore/go-lzo v0.1.0 // indirect
github.com/djherbis/times v1.6.0 // indirect
github.com/elliotwutingfeng/asciiset v0.0.0-20260129054604-cfde2086bc57 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/pierrec/lz4/v4 v4.1.26 // indirect
github.com/pkg/xattr v0.4.12 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
)
+36 -2
View File
@@ -1,10 +1,44 @@
github.com/anchore/go-lzo v0.1.0 h1:NgAacnzqPeGH49Ky19QKLBZEuFRqtTG9cdaucc3Vncs=
github.com/anchore/go-lzo v0.1.0/go.mod h1:3kLx0bve2oN1iDwgM1U5zGku1Tfbdb0No5qp1eL1fIk=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/diskfs/go-diskfs v1.9.4 h1:0j2d7eG4IjyxL6+ChWbDPocdBCF6HQ4HBWU2WDYWVnc=
github.com/diskfs/go-diskfs v1.9.4/go.mod h1:TePJORO83Adh5pb2SqsxAwaP0fofFxKLkxctiS/9OQc=
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
github.com/elliotwutingfeng/asciiset v0.0.0-20260129054604-cfde2086bc57 h1:x5yxNrq8XffV/OoNUeFPM6hxHVi5OTspSTBxr/9pemg=
github.com/elliotwutingfeng/asciiset v0.0.0-20260129054604-cfde2086bc57/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jchv/go-webview2 v0.0.0-20260205173254-56598839c808 h1:ftnsTqIUH57XQEF+PnXX9++nlHCzdkuB5zbWyMMruZo=
github.com/jchv/go-webview2 v0.0.0-20260205173254-56598839c808/go.mod h1:rWifBlzkgrvd7zUqlfq91sWt3473OikgnglnIILx/Jo=
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 h1:njuLRcjAuMKr7kI3D85AXWkw6/+v9PwtV6M6o11sWHQ=
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY=
github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM=
github.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+1 -1
View File
@@ -39,7 +39,7 @@ func Fetch(ctx context.Context, rawURL string) ([]Item, error) {
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "Navis/1.4.0")
req.Header.Set("User-Agent", "Navis/1.4.1")
client := &http.Client{Timeout: 45 * time.Second}
resp, err := client.Do(req)
if err != nil {
+5 -1
View File
@@ -17,7 +17,7 @@ import (
)
// CurrentVersion is the shipped client version.
const CurrentVersion = "1.4.0"
const CurrentVersion = "1.4.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"
@@ -28,6 +28,10 @@ type PlatformAsset struct {
SHA256 string `json:"sha256,omitempty"`
OS string `json:"os,omitempty"`
Arch string `json:"arch,omitempty"`
DmgURL string `json:"dmg_url,omitempty"`
DmgSHA256 string `json:"dmg_sha256,omitempty"`
ZipURL string `json:"zip_url,omitempty"`
ZipSHA256 string `json:"zip_sha256,omitempty"`
}
// Manifest describes a remote release (multi-platform + legacy single URL).
+16 -8
View File
@@ -1,30 +1,38 @@
{
"version": "1.4.0",
"notes": "macOS CLI (arm64/amd64), multi-platform updates, networksetup proxy, naive tar.xz",
"version": "1.4.1",
"notes": "macOS DMG + Navis.app.zip в релизе (arm64/amd64)",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "110ab8f5806f2635b39ec586d8218120d0041a82212715530ae8c3838078bf11",
"sha256": "4217542dfa49a60d522295267b9bd7f3a838b2917b68d9ee59041abecf149e09",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "110ab8f5806f2635b39ec586d8218120d0041a82212715530ae8c3838078bf11",
"sha256": "4217542dfa49a60d522295267b9bd7f3a838b2917b68d9ee59041abecf149e09",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "4ce2b429fe4c8e8e1fdf776150003e42e4452e9ecf95cb55a714f84884717fd6",
"sha256": "a3bc2bcc256842d3914c44385a5fb9b61e691be2c19a9c283bc2099fcc48af9a",
"os": "darwin",
"arch": "arm64"
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
"dmg_sha256": "a49584770e7453e7046ba80a4da8ac84a34797e3a8e4eb307a3d572d1fc95b59",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip",
"zip_sha256": "436c8c0382bf4491d288f6899d1a8fb0f7cd86b53063801f9dbc03f29a92046d"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "a91bc03c7c68d896c42bb3520010e96191c12a0e95e2b9c2582dd2732637d9af",
"sha256": "a1471b447e481e3fe61a65bb66c8633facd968087907e561584fd845842805fb",
"os": "darwin",
"arch": "amd64"
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
"dmg_sha256": "eca2127f956959c1a4567dece779bfcd4bd414d2f63f430c24b133456fa5c56a",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip",
"zip_sha256": "de039f591032dbcf69e81499074cf7f51b80c83f08958521df9b8f873d2fe7be"
}
}
}
+354
View File
@@ -0,0 +1,354 @@
package main
import (
"archive/zip"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
diskfs "github.com/diskfs/go-diskfs"
"github.com/diskfs/go-diskfs/disk"
"github.com/diskfs/go-diskfs/filesystem"
"github.com/diskfs/go-diskfs/filesystem/iso9660"
)
func main() {
bin := flag.String("bin", "", "path to darwin Navis binary")
outDir := flag.String("out", "", "output directory (e.g. dist/navis-release/darwin-arm64)")
version := flag.String("version", "1.4.1", "CFBundleShortVersionString")
arch := flag.String("arch", "arm64", "arch label for volume name")
flag.Parse()
if *bin == "" || *outDir == "" {
fmt.Fprintln(os.Stderr, "usage: packmac -bin <Navis> -out <dir> [-version 1.4.1] [-arch arm64]")
os.Exit(2)
}
if err := run(*bin, *outDir, *version, *arch); err != nil {
fmt.Fprintf(os.Stderr, "packmac: %v\n", err)
os.Exit(1)
}
}
func run(binPath, outDir, version, arch string) error {
if err := os.MkdirAll(outDir, 0o755); err != nil {
return err
}
stage, err := os.MkdirTemp("", "navis-packmac-*")
if err != nil {
return err
}
defer os.RemoveAll(stage)
appRoot := filepath.Join(stage, "Navis.app")
if err := writeAppBundle(appRoot, binPath, version); err != nil {
return err
}
readme := filepath.Join(stage, "README.txt")
if err := os.WriteFile(readme, []byte(readmeText(version, arch)), 0o644); err != nil {
return err
}
zipPath := filepath.Join(outDir, "Navis.app.zip")
if err := zipDir(zipPath, stage, []string{"Navis.app", "README.txt"}); 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 {
return fmt.Errorf("dmg: %w", err)
}
fmt.Println("wrote", dmgPath)
return nil
}
func writeAppBundle(appRoot, binPath, version string) error {
macOSDir := filepath.Join(appRoot, "Contents", "MacOS")
if err := os.MkdirAll(macOSDir, 0o755); err != nil {
return err
}
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">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key><string>Navis</string>
<key>CFBundleIdentifier</key><string>win.evilfox.navis</string>
<key>CFBundleName</key><string>Navis</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleShortVersionString</key><string>%s</string>
<key>CFBundleVersion</key><string>%s</string>
<key>LSMinimumSystemVersion</key><string>11.0</string>
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
</dict>
</plist>
`, version, version)
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil {
return err
}
dest := filepath.Join(macOSDir, "Navis")
if err := copyFile(binPath, dest, 0o755); err != nil {
return err
}
return nil
}
func writeDMG(dmgPath, appRoot, readmePath, volume string) error {
_ = os.Remove(dmgPath)
appSize, err := dirSize(appRoot)
if err != nil {
return err
}
readmeSize, err := fileSize(readmePath)
if err != nil {
return err
}
need := appSize + readmeSize + 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)
if err != nil {
return err
}
mydisk.LogicalBlocksize = 2048
fs, err := mydisk.CreateFilesystem(disk.FilesystemSpec{
Partition: 0,
FSType: filesystem.TypeISO9660,
VolumeLabel: sanitizeVol(volume),
})
if err != nil {
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
}
iso, ok := fs.(*iso9660.FileSystem)
if !ok {
_ = fs.Close()
return fmt.Errorf("not iso9660")
}
if err := iso.Finalize(iso9660.FinalizeOptions{
RockRidge: true,
Joliet: true,
DeepDirectories: true,
VolumeIdentifier: sanitizeVol(volume),
PublisherIdentifier: "Navis",
}); err != nil {
return err
}
return fs.Close()
}
func copyTreeToISO(fs filesystem.FileSystem, srcRoot, dstRoot string) error {
return filepath.Walk(srcRoot, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(srcRoot, path)
if err != nil {
return err
}
rel = filepath.ToSlash(rel)
dst := dstRoot
if rel != "." {
dst = dstRoot + "/" + rel
}
if info.IsDir() {
if dst == dstRoot {
return fs.Mkdir(dst)
}
return fs.Mkdir(dst)
}
mode := info.Mode()
if mode&0o111 != 0 || strings.HasSuffix(rel, "MacOS/Navis") || strings.HasSuffix(rel, "MacOS\\Navis") {
mode = 0o755
} else {
mode = 0o644
}
return writeISOFile(fs, dst, path, mode)
})
}
func writeISOFile(fs filesystem.FileSystem, dst, src string, mode os.FileMode) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
rw, err := fs.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC)
if err != nil {
return err
}
if _, err := io.Copy(rw, in); err != nil {
_ = rw.Close()
return err
}
if err := rw.Close(); err != nil {
return err
}
if err := fs.Chmod(dst, mode); err != nil {
_ = err // best-effort
}
return nil
}
func zipDir(zipPath, stage string, entries []string) error {
_ = os.Remove(zipPath)
f, err := os.Create(zipPath)
if err != nil {
return err
}
defer f.Close()
zw := zip.NewWriter(f)
defer zw.Close()
for _, name := range entries {
root := filepath.Join(stage, name)
info, err := os.Stat(root)
if err != nil {
return err
}
if !info.IsDir() {
if err := addZipFile(zw, root, name, 0o644); err != nil {
return err
}
continue
}
err = filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(stage, path)
if err != nil {
return err
}
rel = filepath.ToSlash(rel)
if fi.IsDir() {
_, err := zw.Create(rel + "/")
return err
}
mode := os.FileMode(0o644)
if strings.Contains(rel, "Contents/MacOS/") {
mode = 0o755
}
return addZipFile(zw, path, rel, mode)
})
if err != nil {
return err
}
}
return nil
}
func addZipFile(zw *zip.Writer, path, name string, mode os.FileMode) error {
h, err := zip.FileInfoHeader(mustStat(path))
if err != nil {
return err
}
h.Name = name
h.Method = zip.Deflate
h.SetMode(mode)
w, err := zw.CreateHeader(h)
if err != nil {
return err
}
in, err := os.Open(path)
if err != nil {
return err
}
defer in.Close()
_, err = io.Copy(w, in)
return err
}
func mustStat(path string) os.FileInfo {
fi, err := os.Stat(path)
if err != nil {
panic(err)
}
return fi
}
func copyFile(src, dst string, mode os.FileMode) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
return err
}
func dirSize(root string) (int64, error) {
var n int64
err := filepath.Walk(root, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
n += info.Size()
}
return nil
})
return n, err
}
func fileSize(path string) (int64, error) {
fi, err := os.Stat(path)
if err != nil {
return 0, err
}
return fi.Size(), nil
}
func sanitizeVol(s string) string {
s = strings.ToUpper(s)
s = strings.Map(func(r rune) rune {
if (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '-' || r == '_' {
return r
}
return '-'
}, s)
if len(s) > 32 {
s = s[:32]
}
if s == "" {
s = "NAVIS"
}
return s
}
func readmeText(version, arch string) string {
return fmt.Sprintf(`Navis %s for macOS (%s)
1) Open this disk image
2) Drag Navis.app to Applications (or any folder)
3) First launch may need:
xattr -dr com.apple.quarantine /Applications/Navis.app
4) Run from Terminal:
/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).
Shop: https://evilfox.win/
`, version, arch)
}
+4 -4
View File
@@ -1,7 +1,7 @@
{
"FixedFileInfo": {
"FileVersion": { "Major": 1, "Minor": 4, "Patch": 0, "Build": 0 },
"ProductVersion": { "Major": 1, "Minor": 4, "Patch": 0, "Build": 0 },
"FileVersion": { "Major": 1, "Minor": 4, "Patch": 1, "Build": 0 },
"ProductVersion": { "Major": 1, "Minor": 4, "Patch": 1, "Build": 0 },
"FileFlagsMask": "3f",
"FileFlags": "00",
"FileOS": "40004",
@@ -11,11 +11,11 @@
"StringFileInfo": {
"CompanyName": "Navis",
"FileDescription": "Navis — NaiveProxy / Hysteria 2 client for Windows and macOS",
"FileVersion": "1.4.0.0",
"FileVersion": "1.4.1.0",
"InternalName": "Navis",
"OriginalFilename": "Navis.exe",
"ProductName": "Navis",
"ProductVersion": "1.4.0.0"
"ProductVersion": "1.4.1.0"
},
"VarFileInfo": {
"Translation": {