Release 1.6.1: fix subscription button stuck disabled and improve import parsing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-07-28 09:00:59 +03:00
co-authored by Cursor
parent 68a48b05ef
commit 740517dbfb
16 changed files with 258 additions and 68 deletions
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.
+10 -10
View File
@@ -1,38 +1,38 @@
{
"version": "1.6.0",
"notes": "Windows: полноценные кнопки вместо «надписей»; версия 1.6.0",
"version": "1.6.1",
"notes": "Фикс URL подписки: кнопка ↻ снова работает, сообщения об ошибке/успехе видны, лучше парсинг base64/Clash",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "5581e090ce94b7743cedcf721b32eb4b3449fc74f89d54cd7bf6a6b828cb2fab",
"sha256": "b836310af1b946c98d5d84787266d79978cb6d2a45e360c9fc5cb3a0a89059e4",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "5581e090ce94b7743cedcf721b32eb4b3449fc74f89d54cd7bf6a6b828cb2fab",
"sha256": "b836310af1b946c98d5d84787266d79978cb6d2a45e360c9fc5cb3a0a89059e4",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "c1727030ec48fcd25f64e28d91bb115bbd41c8c7664545ad9c386976b71c44ce",
"sha256": "94a39a127073ee299902026fe0be6f35506663fb20b9d9dde73f8f7732b1c079",
"os": "darwin",
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
"dmg_sha256": "b0c4e2e2c393372cf4d94004c4888d7c6470f2f3e435833362f0530fc0bea413",
"dmg_sha256": "1880a4bac8f52e5ea0ed4f5ed6a6d796f492347a7bb1b0565b6766859839d04a",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip",
"zip_sha256": "8f6816cc002f3a66938c7b5d4b09d8ca6920dbfd73670848bc51c08d1be1fc8c"
"zip_sha256": "16711d3c0544806eefa0ca29b0d2c78b9f159c44e4e526cf05ce9ec1aaf82af9"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "6f7978428bccde576c12fc175b40a3590d300006437dd3eaf31182dce9104943",
"sha256": "580005bbdaeef92ae6384be7946cef103c45b1150473185bdf70538d77e3b545",
"os": "darwin",
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
"dmg_sha256": "ff2ef6d0893547b290193874cd87d51f1d1ca6232071877d443cdf3506566ef8",
"dmg_sha256": "d80bd24e467886db6fd8486f5e209cb835531b2665bac953267d0fee959dd9c0",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip",
"zip_sha256": "51eb1847abf0b34d8b061680118c94df3e2340c5382d2a718bbef41ddbf19abc"
"zip_sha256": "d6e9876ce1a7331f9fd9f8bece86a6bce55a48d874c6e40d22292653029dc486"
}
}
}
+10 -10
View File
@@ -1,38 +1,38 @@
{
"version": "1.6.0",
"notes": "Windows: полноценные кнопки вместо «надписей»; версия 1.6.0",
"version": "1.6.1",
"notes": "Фикс URL подписки: кнопка ↻ снова работает, сообщения об ошибке/успехе видны, лучше парсинг base64/Clash",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "5581e090ce94b7743cedcf721b32eb4b3449fc74f89d54cd7bf6a6b828cb2fab",
"sha256": "b836310af1b946c98d5d84787266d79978cb6d2a45e360c9fc5cb3a0a89059e4",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "5581e090ce94b7743cedcf721b32eb4b3449fc74f89d54cd7bf6a6b828cb2fab",
"sha256": "b836310af1b946c98d5d84787266d79978cb6d2a45e360c9fc5cb3a0a89059e4",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "c1727030ec48fcd25f64e28d91bb115bbd41c8c7664545ad9c386976b71c44ce",
"sha256": "94a39a127073ee299902026fe0be6f35506663fb20b9d9dde73f8f7732b1c079",
"os": "darwin",
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
"dmg_sha256": "b0c4e2e2c393372cf4d94004c4888d7c6470f2f3e435833362f0530fc0bea413",
"dmg_sha256": "1880a4bac8f52e5ea0ed4f5ed6a6d796f492347a7bb1b0565b6766859839d04a",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip",
"zip_sha256": "8f6816cc002f3a66938c7b5d4b09d8ca6920dbfd73670848bc51c08d1be1fc8c"
"zip_sha256": "16711d3c0544806eefa0ca29b0d2c78b9f159c44e4e526cf05ce9ec1aaf82af9"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "6f7978428bccde576c12fc175b40a3590d300006437dd3eaf31182dce9104943",
"sha256": "580005bbdaeef92ae6384be7946cef103c45b1150473185bdf70538d77e3b545",
"os": "darwin",
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
"dmg_sha256": "ff2ef6d0893547b290193874cd87d51f1d1ca6232071877d443cdf3506566ef8",
"dmg_sha256": "d80bd24e467886db6fd8486f5e209cb835531b2665bac953267d0fee959dd9c0",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip",
"zip_sha256": "51eb1847abf0b34d8b061680118c94df3e2340c5382d2a718bbef41ddbf19abc"
"zip_sha256": "d6e9876ce1a7331f9fd9f8bece86a6bce55a48d874c6e40d22292653029dc486"
}
}
}
+36 -8
View File
@@ -555,6 +555,7 @@
let formHydrated = false;
let dirty = false;
let profiles = [];
let metaHoldUntil = 0;
function markDirty() { dirty = true; }
[
@@ -571,6 +572,7 @@
function setMeta(text, kind) {
meta.textContent = text || "";
meta.style.color = kind === "err" ? "var(--danger)" : kind === "ok" ? "var(--accent)" : "var(--muted)";
if (kind === "ok" || kind === "err") metaHoldUntil = Date.now() + 8000;
}
function fillProfiles(list, active) {
@@ -640,6 +642,8 @@
pingBtn.disabled = busy;
updCheckBtn.disabled = busy;
updateBtn.disabled = busy;
subBtn.disabled = busy;
subUrl.disabled = busy;
btn.disabled = busy;
fillProfiles(state.profiles || [], state.active_profile || state.profile);
@@ -670,7 +674,10 @@
} else {
detail = "Вставьте ссылку naive или hysteria2://";
}
if (!busy) setMeta(detail, state.core_ready === false ? "err" : "");
if (!busy && Date.now() > metaHoldUntil) {
setMeta(detail, state.core_ready === false ? "err" : "");
metaHoldUntil = 0;
}
}
async function refresh(opts) {
@@ -682,7 +689,7 @@
async function withBusy(fn) {
if (busy) return;
busy = true;
[btn, coreBtn, saveBtn, addBtn, delBtn, profile, pingBtn, updCheckBtn, updateBtn, subBtn].forEach((b) => { if (b) b.disabled = true; });
paintButtonsLocked(true);
try {
await fn();
} finally {
@@ -691,11 +698,17 @@
await refresh({ syncForm: true });
} catch (e) {
setMeta(String(e), "err");
[btn, coreBtn, saveBtn, addBtn, delBtn, profile, pingBtn, updCheckBtn, updateBtn, subBtn].forEach((b) => { if (b) b.disabled = false; });
paintButtonsLocked(false);
}
}
}
function paintButtonsLocked(locked) {
[btn, coreBtn, saveBtn, addBtn, delBtn, profile, pingBtn, updCheckBtn, updateBtn, subBtn, subUrl].forEach((b) => {
if (b) b.disabled = locked;
});
}
profile.addEventListener("change", () => withBusy(async () => {
await selectProfile(profile.value);
dirty = false;
@@ -780,15 +793,30 @@
shopBtn.addEventListener("click", openShop);
shopLink.addEventListener("click", openShop);
async function runImportSubscription() {
const url = subUrl.value.trim();
if (!url) {
setMeta("Вставьте URL подписки", "err");
return;
}
setMeta("Загрузка подписки…");
const n = await importSubscription(url);
formHydrated = false;
dirty = false;
setMeta("Импортировано профилей: " + n, "ok");
}
subBtn.addEventListener("click", () => withBusy(async () => {
try {
setMeta("Загрузка подписки…");
const n = await importSubscription(subUrl.value.trim());
formHydrated = false;
dirty = false;
setMeta("Импортировано профилей: " + n, "ok");
await runImportSubscription();
} catch (e) { setMeta(String(e), "err"); }
}));
subUrl.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
subBtn.click();
}
});
pingBtn.addEventListener("click", () => withBusy(async () => {
try {
+3 -7
View File
@@ -404,19 +404,15 @@ func (m *Manager) SubscriptionURL() string {
}
func (m *Manager) ImportSubscription(rawURL string) (int, error) {
m.mu.Lock()
if m.engine != nil && m.engine.Running() {
m.mu.Unlock()
return 0, fmt.Errorf("сначала отключитесь")
}
m.mu.Unlock()
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
items, err := subscription.Fetch(ctx, rawURL)
if err != nil {
return 0, err
}
if len(items) == 0 {
return 0, fmt.Errorf("в подписке нет поддерживаемых ссылок (naive / hysteria2)")
}
m.mu.Lock()
defer m.mu.Unlock()
+140 -17
View File
@@ -7,6 +7,7 @@ import (
"io"
"net/http"
"net/url"
"regexp"
"strings"
"time"
"unicode"
@@ -24,6 +25,11 @@ type Item struct {
URI string
}
var (
reShareLine = regexp.MustCompile(`(?i)((?:hysteria2|hy2|naive\+https|naive\+quic|naive|quic|https|http)://[^\s"'<>]+)`)
reClashHY2 = regexp.MustCompile(`(?is)type:\s*hysteria2\b.*?server:\s*(\S+).*?port:\s*(\d+).*?(?:password|auth):\s*["']?([^\s"']+)`)
)
// Fetch downloads a subscription body and parses proxy share links.
func Fetch(ctx context.Context, rawURL string) ([]Item, error) {
rawURL = strings.TrimSpace(rawURL)
@@ -39,53 +45,96 @@ func Fetch(ctx context.Context, rawURL string) ([]Item, error) {
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "Navis/1.6.0")
req.Header.Set("User-Agent", "ClashMeta/1.18.0")
req.Header.Set("Accept", "*/*")
client := &http.Client{Timeout: 45 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("не удалось скачать подписку: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("подписка HTTP %d", resp.StatusCode)
}
body, err := io.ReadAll(io.LimitReader(resp.Body, 8<<20))
if err != nil {
return nil, err
}
return ParseBody(string(body))
items, err := ParseBody(string(body))
if err != nil {
return nil, err
}
return items, nil
}
// ParseBody accepts plain text lines or base64 (Clash/V2Ray style subscription).
// ParseBody accepts plain text lines, base64, or Clash-like blobs with share links.
func ParseBody(body string) ([]Item, error) {
body = strings.TrimSpace(body)
if body == "" {
return nil, fmt.Errorf("пустая подписка")
}
text := body
if !looksLikeLinks(body) {
if decoded, err := decodeMaybeBase64(body); err == nil && looksLikeLinks(decoded) {
text = decoded
candidates := []string{body}
if decoded, err := decodeMaybeBase64(body); err == nil && decoded != "" && decoded != body {
candidates = append(candidates, decoded)
// some panels double-encode
if decoded2, err2 := decodeMaybeBase64(decoded); err2 == nil && decoded2 != "" && decoded2 != decoded {
candidates = append(candidates, decoded2)
}
}
var lastErr error
for _, text := range candidates {
items, err := parseText(text)
if err == nil && len(items) > 0 {
return items, nil
}
if err != nil {
lastErr = err
}
}
if lastErr != nil {
return nil, lastErr
}
return nil, fmt.Errorf("в подписке нет поддерживаемых ссылок (naive / hysteria2)")
}
func parseText(text string) ([]Item, error) {
lines := splitLines(text)
// Also extract share URIs embedded in YAML/HTML/JSON.
extracted := reShareLine.FindAllString(text, -1)
for _, m := range extracted {
lines = append(lines, strings.TrimRight(m, ".,;)]}\"'"))
}
for _, block := range extractClashHY2(text) {
lines = append(lines, block)
}
out := make([]Item, 0, len(lines))
seen := map[string]int{}
seenURI := map[string]struct{}{}
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
// Some panels wrap links in quotes
line = strings.Trim(line, `"'`)
proto := config.DetectProtocol(line)
if proto == "" {
continue
}
// Skip bare https:// without credentials (common noise in HTML/YAML).
if proto == config.ProtocolNaive && !naiveLinkHasAuth(line) && !strings.HasPrefix(strings.ToLower(line), "naive+") {
continue
}
normalized, detected, remark, err := linknorm.Normalize(proto, line)
if err != nil {
continue
}
if _, dup := seenURI[normalized]; dup {
continue
}
seenURI[normalized] = struct{}{}
name := remark
if name == "" {
name = defaultName(detected, normalized)
@@ -106,13 +155,81 @@ func ParseBody(body string) ([]Item, error) {
return out, nil
}
func looksLikeLinks(s string) bool {
lower := strings.ToLower(s)
return strings.Contains(lower, "hysteria2://") ||
strings.Contains(lower, "hy2://") ||
strings.Contains(lower, "naive+") ||
strings.Contains(lower, "https://") ||
strings.Contains(lower, "quic://")
func naiveLinkHasAuth(line string) bool {
lower := strings.ToLower(strings.TrimSpace(line))
for _, p := range []string{"naive+https://", "naive+quic://", "naive://", "https://", "http://", "quic://"} {
if strings.HasPrefix(lower, p) {
rest := line[len(p):]
at := strings.IndexByte(rest, '@')
return at > 0
}
}
return false
}
func extractClashHY2(text string) []string {
// Very small helper for Clash YAML hysteria2 blocks when share URI is absent.
lower := strings.ToLower(text)
if !strings.Contains(lower, "type:") || !strings.Contains(lower, "hysteria2") {
return nil
}
var out []string
// Split roughly by list items.
chunks := strings.Split(text, "\n- ")
for _, chunk := range chunks {
cl := strings.ToLower(chunk)
if !strings.Contains(cl, "type:") || !strings.Contains(cl, "hysteria2") {
continue
}
server := yamlField(chunk, "server")
port := yamlField(chunk, "port")
pass := yamlField(chunk, "password")
if pass == "" {
pass = yamlField(chunk, "auth")
}
if server == "" || port == "" || pass == "" {
continue
}
name := yamlField(chunk, "name")
sni := yamlField(chunk, "sni")
obfs := yamlField(chunk, "obfs")
obfsPass := yamlField(chunk, "obfs-password")
if obfsPass == "" {
obfsPass = yamlField(chunk, "obfs_password")
}
u := url.URL{
Scheme: "hysteria2",
User: url.User(pass),
Host: server + ":" + port,
}
q := url.Values{}
if sni != "" {
q.Set("sni", sni)
}
if obfs != "" {
q.Set("obfs", obfs)
}
if obfsPass != "" {
q.Set("obfs-password", obfsPass)
}
u.RawQuery = q.Encode()
link := u.String()
if name != "" {
link += "#" + url.PathEscape(name)
}
out = append(out, link)
}
_ = reClashHY2 // kept for possible future tightening
return out
}
func yamlField(block, key string) string {
re := regexp.MustCompile(`(?im)^\s*` + regexp.QuoteMeta(key) + `\s*:\s*["']?([^"'#\n\r]+)["']?`)
m := re.FindStringSubmatch(block)
if len(m) < 2 {
return ""
}
return strings.TrimSpace(m[1])
}
func decodeMaybeBase64(s string) (string, error) {
@@ -122,6 +239,9 @@ func decodeMaybeBase64(s string) (string, error) {
}
return r
}, s)
if s == "" {
return "", fmt.Errorf("empty")
}
raw, err := base64.StdEncoding.DecodeString(s)
if err != nil {
raw, err = base64.RawStdEncoding.DecodeString(s)
@@ -129,6 +249,9 @@ func decodeMaybeBase64(s string) (string, error) {
if err != nil {
raw, err = base64.URLEncoding.DecodeString(s)
}
if err != nil {
raw, err = base64.RawURLEncoding.DecodeString(s)
}
if err != nil {
return "", err
}
+44 -1
View File
@@ -1,6 +1,10 @@
package subscription
import "testing"
import (
"encoding/base64"
"strings"
"testing"
)
func TestParseBodyPlain(t *testing.T) {
body := `# comment
@@ -15,3 +19,42 @@ naive+https://u:p@n.example.com#naive1
t.Fatalf("got %d items", len(items))
}
}
func TestParseBodyBase64(t *testing.T) {
plain := "hysteria2://secret@host.example:443/?sni=host.example#HY\nhttps://user:pass@naive.example.com#NV\n"
body := base64.StdEncoding.EncodeToString([]byte(plain))
items, err := ParseBody(body)
if err != nil {
t.Fatal(err)
}
if len(items) != 2 {
t.Fatalf("got %d items: %+v", len(items), items)
}
}
func TestParseBodyClashYAML(t *testing.T) {
body := `
proxies:
- name: "DE HY2"
type: hysteria2
server: de.example.com
port: 443
password: secret
sni: de.example.com
obfs: salamander
obfs-password: obfspass
`
items, err := ParseBody(body)
if err != nil {
t.Fatal(err)
}
if len(items) != 1 {
t.Fatalf("got %d", len(items))
}
if items[0].Protocol != "hysteria2" {
t.Fatalf("proto %s", items[0].Protocol)
}
if !strings.Contains(items[0].URI, "de.example.com:443") {
t.Fatalf("uri %s", items[0].URI)
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ import (
)
// CurrentVersion is the shipped client version.
const CurrentVersion = "1.6.0"
const CurrentVersion = "1.6.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"
+10 -10
View File
@@ -1,38 +1,38 @@
{
"version": "1.6.0",
"notes": "Windows: полноценные кнопки вместо «надписей»; версия 1.6.0",
"version": "1.6.1",
"notes": "Фикс URL подписки: кнопка ↻ снова работает, сообщения об ошибке/успехе видны, лучше парсинг base64/Clash",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "5581e090ce94b7743cedcf721b32eb4b3449fc74f89d54cd7bf6a6b828cb2fab",
"sha256": "b836310af1b946c98d5d84787266d79978cb6d2a45e360c9fc5cb3a0a89059e4",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "5581e090ce94b7743cedcf721b32eb4b3449fc74f89d54cd7bf6a6b828cb2fab",
"sha256": "b836310af1b946c98d5d84787266d79978cb6d2a45e360c9fc5cb3a0a89059e4",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "c1727030ec48fcd25f64e28d91bb115bbd41c8c7664545ad9c386976b71c44ce",
"sha256": "94a39a127073ee299902026fe0be6f35506663fb20b9d9dde73f8f7732b1c079",
"os": "darwin",
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
"dmg_sha256": "b0c4e2e2c393372cf4d94004c4888d7c6470f2f3e435833362f0530fc0bea413",
"dmg_sha256": "1880a4bac8f52e5ea0ed4f5ed6a6d796f492347a7bb1b0565b6766859839d04a",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.app.zip",
"zip_sha256": "8f6816cc002f3a66938c7b5d4b09d8ca6920dbfd73670848bc51c08d1be1fc8c"
"zip_sha256": "16711d3c0544806eefa0ca29b0d2c78b9f159c44e4e526cf05ce9ec1aaf82af9"
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "6f7978428bccde576c12fc175b40a3590d300006437dd3eaf31182dce9104943",
"sha256": "580005bbdaeef92ae6384be7946cef103c45b1150473185bdf70538d77e3b545",
"os": "darwin",
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
"dmg_sha256": "ff2ef6d0893547b290193874cd87d51f1d1ca6232071877d443cdf3506566ef8",
"dmg_sha256": "d80bd24e467886db6fd8486f5e209cb835531b2665bac953267d0fee959dd9c0",
"zip_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.app.zip",
"zip_sha256": "51eb1847abf0b34d8b061680118c94df3e2340c5382d2a718bbef41ddbf19abc"
"zip_sha256": "d6e9876ce1a7331f9fd9f8bece86a6bce55a48d874c6e40d22292653029dc486"
}
}
}
+4 -4
View File
@@ -1,7 +1,7 @@
{
"FixedFileInfo": {
"FileVersion": { "Major": 1, "Minor": 6, "Patch": 0, "Build": 0 },
"ProductVersion": { "Major": 1, "Minor": 6, "Patch": 0, "Build": 0 },
"FileVersion": { "Major": 1, "Minor": 6, "Patch": 1, "Build": 0 },
"ProductVersion": { "Major": 1, "Minor": 6, "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.6.0.0",
"FileVersion": "1.6.1.0",
"InternalName": "Navis",
"OriginalFilename": "Navis.exe",
"ProductName": "Navis",
"ProductVersion": "1.6.0.0"
"ProductVersion": "1.6.1.0"
},
"VarFileInfo": {
"Translation": {