Commit Graph

1336 Commits

Author SHA1 Message Date
luantu
f9c841a6f6 feat: auto-switch profile by WiFi SSID
* feat: auto-switch profile by WiFi SSID

Add ssidProfileMap (SSID -> profile ID) and ssidProfileRestore to app config.
When connecting to a mapped WiFi SSID, automatically switch to the
corresponding subscription profile. Optionally restore the previous
profile when leaving the mapped SSID. pauseSSID takes priority.

* fix: send profileConfigUpdated after SSID-triggered profile switch

changeCurrentProfile() does not notify the renderer via IPC.
The renderer relies on the profileConfigUpdated event to revalidate
its SWR cache, so SSID-based switching was effective in the backend
but the UI didn't reflect it until a manual refresh.

* perf: event-driven SSID detection on macOS via scutil -w

Replace 30s polling with scutil -w child process on macOS.
scutil -w blocks on a SystemConfiguration key, consuming zero CPU
until the network state changes, then exits. On exit we debounce
500ms and re-check the SSID.

Windows/Linux keep polling, reduced from 30s to 15s.
Also add anti-tight-loop guard (1s minimum restart interval).
2026-08-20 10:17:47 +08:00
MOMO0302-02
588aaa6991 fix: prevent command injection in convertMrsRuleset
convertMrsRuleset built a shell command string from `behavior` and the
resolved ruleset path and ran it through `exec`. `behavior` comes from
the runtime config's `rule-providers`, which originates from the user's
subscription YAML and is therefore untrusted input.

A malicious or compromised subscription can set a behavior such as
`domain & <command> &`; opening that ruleset in the resource viewer then
executes arbitrary commands with the app's privileges. The quoted paths
are also breakable on Windows via an embedded double quote.

Switch to `execFile` with an argument array so nothing is parsed by a
shell, and reject any behavior outside the set the core supports.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 10:16:50 +08:00
MOMO0302-02
316c41c05b ci: run lint, typecheck, format and unit tests on PRs and pushes
The existing build.yml only runs on v* tags and never invokes the test
suite, so pull requests get no automated checks. Add a lightweight CI
workflow that runs format:check, lint:check and typecheck once on Linux
and the unit tests on both Linux and Windows. Uses --ignore-scripts so it
does not download the mihomo cores, which the checks and tests do not need.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-20 10:12:19 +08:00
MOMO0302-02
c779799bee ci: staple the notarization ticket to the macOS pkg
The macos and macos10 jobs submit the signed .pkg to notarytool but never
staple the resulting ticket to it. Without a stapled ticket Gatekeeper has to
reach Apple's notary service to verify the package, so an install on a machine
that is offline — or behind a blocked network, which is a plausible state for
this particular app before it is running — fails with "cannot be opened because
Apple cannot check it for malicious software".

Staple after a successful submission, which is the documented final step of the
Developer ID distribution flow.
2026-08-20 10:10:21 +08:00
zjdndjf
4e86b53db7 fix: preserve Smart model in profile work dirs 2026-08-19 14:07:46 +08:00
zjdndjf
2330e7790e feat: support custom GitHub download proxy (#2096) 2026-08-19 13:30:01 +08:00
zjdndjf
fca31a84b3 fix: crash when geo-update-interval is null in config 2026-08-17 10:54:12 +08:00
Shen Zehou
41c2f26538 fix: load legacy sysproxy binding on Windows 8/8.1 2026-08-16 10:05:52 +08:00
Memory
cf13cb9d28 fix Windows ARM64 NSIS installer 2026-08-15 13:00:53 +08:00
Memory2314
ec8bfc542a chore: bump version v2.0.2 2026-08-14 22:55:28 +08:00
Memory2314
354c4e6385 update changelog 2026-08-14 22:54:55 +08:00
Memory
48c703a354 revert: downgrade Electron to 43.2.0 2026-08-14 22:46:43 +08:00
zjdndjf
3fc2223448 docs: add AGENTS.md and CLAUDE.md restricting AI agents from bypassing commit checks 2026-08-13 05:28:32 +08:00
zjdndjf
147ecaa7d9 chore: skip pnpm verify-deps auto-install on script runs 2026-08-13 05:21:16 +08:00
zjdndjf
60dba7895d fix: use valid popover side for welcome tour step 2026-08-13 05:07:07 +08:00
zjdndjf
f4a4d9b31d fix: use valid Electron accelerator names for numpad operator keys 2026-08-13 05:05:51 +08:00
shenmo
c89e21b782 ci(github actions): fix cross-compile arch issue for prepare step (#2075)
1. 为CI的Prepare步骤添加npm_config_arch和target_arch环境变量
2. 重构架构解析逻辑,支持从环境变量读取目标架构
3. 添加ELF架构校验,防止交叉编译时混入错误架构的二进制文件
2026-08-13 04:38:22 +08:00
Memory
356f9817f0 chore: bump version v2.0.1 2026-08-11 20:34:07 +08:00
Memory
a985eb867a update changelog 2026-08-11 20:33:14 +08:00
Memory
043ab2def0 chore: update dependencies and migrate to pnpm 11 2026-08-11 20:26:34 +08:00
zjdndjf
6cbd24e30a Revert "fix: stop log streaming when logs page unmounts"
This reverts commit 5532a85164.
2026-08-10 03:34:32 +08:00
zjdndjf
8ed132f735 fix: reject non-mapping tunnel profiles 2026-08-10 02:54:31 +08:00
MOMO0302-02
8d3a62a5e6 fix: do not let the tunnel editor overwrite a profile it failed to read (#2041)
EditTunnelsModal saves by spreading the in-memory `profile` state and
writing the whole document back with setProfileStr, which replaces the
profile file outright and then hot-reloads the core. `profile` starts as
`{}` and is only filled in once the async load succeeds.

Neither failure path stops the user from saving:

  - When yaml.load throws (a subscription with a duplicated mapping key,
    for example) the catch only shows a toast. `profile` stays `{}`, so
    pressing save serialises "{}\n" over the profile and every proxy,
    proxy-group and rule is gone.

  - When the parsed value is not an object the code silently substituted
    `{}` with no toast at all. An age-encrypted profile hits this: the
    file on disk is ciphertext and getProfileStr does not decrypt, so
    yaml.load returns a string, the dialog shows "no tunnels", and saving
    destroys the encrypted profile.

The save button was also enabled while the initial load was still in
flight.

Treat a non-object parse result as an error instead of silently
substituting `{}`, record the failure, and refuse to save - both in
handleSave and by disabling the button - until the profile has actually
been read.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 02:52:28 +08:00
zjdndjf
d9cd7712ab fix: serialize system proxy transitions
Closes #2045
2026-08-10 02:43:50 +08:00
zjdndjf
8b0b1ce0cb fix: avoid workdir setup during profile validation 2026-08-10 02:35:04 +08:00
Feng GAO
e4efc0865f fix: validate remote profiles before replacing them (#2048) 2026-08-10 02:33:38 +08:00
Memory
8af583e771 fix: bundle wl-copy for tray clipboard on Wayland
* fix: bundle wl-copy for tray clipboard on Wayland

* Update changelog.md
2026-08-08 17:08:36 +08:00
ezequielnick
5532a85164 fix: stop log streaming when logs page unmounts
Move the renderer listener into the page effect and gate the main-process log WebSocket on renderer demand. Prevent an in-flight stream startup from surviving page teardown.
2026-08-07 12:40:43 +08:00
agoudbg
aec41f5889 fix: rename border-swtich -> border-switch 2026-08-06 22:02:48 +08:00
zjdndjf
2210eedbdc feat: add independent core log toggle
Closes #414
2026-08-05 20:25:40 +08:00
zjdndjf
5a348fdf04 feat: add hidden proxy groups toggle
Closes #452
2026-08-05 20:25:40 +08:00
zjdndjf
a9e0c6d26f feat: add startup subscription update toggle
Closes #542
2026-08-05 20:25:40 +08:00
Tongyuxiu Zhou
8c297c764d fix: restore main window on second instance launch (#2050) 2026-08-05 19:28:47 +08:00
TonyCrane
d7a79bc054 fix: preserve and recover macOS helper service (#2052) 2026-08-05 19:25:48 +08:00
agoudbg
6b56108ec4 fix: exclude divider height from title bar overlay (#2054) 2026-08-05 00:28:53 +08:00
agoudbg
e9ef676d60 fix: switch style in usage card (#2053) 2026-08-05 00:28:30 +08:00
Memory
5046daaa6d fix: only allow disabling tray icon with floating window 2026-08-01 11:35:26 +08:00
MOMO0302-02
badebd10a4 test: make dirs.test.ts pass on Windows (#2044)
dirs.test.ts asserts on values produced by `path.join`, but compares
them against hardcoded POSIX literals such as
'/tmp/app-data/mihomo-party-dev'. On Windows `path.join` returns
'\tmp\app-data\mihomo-party-dev', so two of the three cases fail on a
clean checkout:

  × isolates an unpackaged local development app
  × keeps portable userData precedence over local development isolation

The fs mock had the same problem: it detected the portable marker with
`value.endsWith('/PORTABLE')`, which never matches the backslash path
that `path.join` produces on Windows.

dirs.ts itself is correct; only the test encodes a platform assumption.
Build the expected values with `path.join` and match the portable
marker with `path.basename`, so the suite is platform-agnostic.

Full suite now passes on Windows 11: 20 files, 176 tests.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 02:06:13 +08:00
MOMO0302-02
0f3d338e3a fix: updater HTTP handling, macOS pkg install path and proxy port (#2042)
* fix: treat HTTP errors as failures in the updater and fix the pkg install path

1. tryDownload returned the first response it got. chromeRequest only
   rejects on transport errors, so an HTTP 404/502 from a mirror was
   returned as success and the remaining mirrors were never tried.
   checkUpdate then ran `parse()` over an HTML error page; the result has
   no `version`, so compareVersions calls `.replace` on undefined and
   throws a TypeError instead of reporting that the check failed. Check
   the status code and throw so the fallback loop keeps going.

2. downloadAndInstallUpdate only cleared updateInstallPromise when
   installUpdate rejected. The macOS .pkg branch catches an osascript
   failure and falls back to `shell.openPath`, which resolves normally
   and leaves the app running. From then on updateInstallPromise held a
   settled promise, so every later attempt returned it immediately and
   the update button did nothing. Clear it in `finally`.

3. The pkg command escaped spaces with `.replace(' ', '\\\\ ')`. A string
   pattern replaces only the first occurrence, and the macOS data
   directory ("~/Library/Application Support/...") contains more than
   one space, so the installer command was still split. Quote the path
   once and escape it for the AppleScript string literal, and invoke
   osascript through execFile so the outer command is not shell-parsed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: validate latest.yml and skip the proxy when the mixed port is off

- checkUpdate parsed latest.yml and used the result without checking it.
  A proxy error page can still parse as YAML (`404: Not Found` is a valid
  mapping), so `latest.version` was undefined and compareVersions threw a
  TypeError on `a.replace` instead of reporting a failed check.

- Both the update check and the download built the proxy from the mixed
  port through a destructuring default, which only covers undefined.
  Turning the port off stores 0, so every request went to 127.0.0.1:0 and
  failed. Go direct when no port is enabled.

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 02:05:58 +08:00
MOMO0302-02
5523129529 fix: restore the real tray icon when the traffic display is turned off (#2039)
Turning the traffic display off sent trayIconUpdate with enabled=false,
but the handler ignores that flag and always applies the supplied data
URL, so the tray kept showing the renderer-composed image until the app
was restarted. Ask the main process to redraw from its own resources
afterwards.

Refs #1080

This covers the "does not recover" half of the report. The colours being
wrong while the traffic display is on has the same root cause as #1143 -
the handler calls setTemplateImage(true) unconditionally, so macOS renders
alpha only - and needs a change in tray.ts.
2026-08-01 02:05:37 +08:00
MOMO0302-02
be1761ea15 fix: notify the renderer after a scheduled subscription update (#2034)
The scheduled updater calls addProfileItem, which never sends
profileConfigUpdated. The subscription list revalidates on that event, so
the "updated N minutes ago" line and the traffic figures stayed stale
until the window regained focus - which reads exactly like the interval
not working. The plugin update path already notifies; only the remote one
did not.

Refs #1570

This addresses the stale UI half of the report. A scheduled update of the
profile that is currently active still writes the new YAML without
reloading it into the running core, because changeCurrentProfile returns
early when the id is unchanged; that part is left for a separate change.
2026-08-01 02:05:15 +08:00
MOMO0302-02
841c3cfe22 fix: harden traffic stream parsing and sysproxy status lookup (#2022)
Two independent robustness defects in mihomoApi.

1. In mihomoTraffic(), `JSON.parse(data)` sat outside the try block,
   unlike the memory, logs and connections streams where it is inside.
   The handler was also `async`, so a non-JSON frame from the core threw
   inside a promise with no rejection handler, producing an
   unhandledRejection instead of being ignored like the other three
   streams. Move the parse inside the try and drop the unnecessary
   `async`.

2. SysProxyStatus() read `appConfig.sysProxy.enable` with no optional
   chaining, while the neighbouring TunStatus() already guards with
   `config?.tun?.enable`. If the app config is missing or truncated,
   sysProxy is undefined and the property access throws. That rejection
   propagates through getTrayIconStatus(), so the tray icon stops
   reflecting the real state. Guard it the same way TunStatus does.

Closes #1286

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 02:04:53 +08:00
zjdndjf
4c168ffa96 fix: validate system proxy bypass formats 2026-08-01 01:29:40 +08:00
Memory
ac7bf09612 fix: validate TUN MTU range 2026-07-28 09:52:04 +08:00
luantu
f9356aa657 feat(traffic): 为详情表格和子行展开添加 loading 动画 2026-07-27 09:56:20 +08:00
zjdndjf
beb54159bf fix: recover core before config push
Closes #2011
2026-07-27 09:44:09 +08:00
Wenjie Fu
0dd6481712 fix: restore macOS connection app icons 2026-07-25 19:11:40 +08:00
Tongyuxiu Zhou
e019290493 feat: redesign airport plugin UI & support per-plugin proxy settings (#2007)
* feat: redesign and streamline the airport plugin interface

* feat: support per-plugin proxy settings
2026-07-23 02:18:21 +08:00
zjdndjf
223b7f46de fix: restore proxy group expansion state
close #2009
2026-07-23 00:49:11 +08:00
zjdndjf
a84c18a7c3 feat: add silent app updates 2026-07-22 03:17:42 +08:00