-
Notifications
You must be signed in to change notification settings - Fork 3
Shortcuts and control center #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
EasyTier/Utils/NEManager.swift
Outdated
| // Save config to App Group for Widget use | ||
| let defaults = UserDefaults(suiteName: "group.site.yinmo.easytier") | ||
| var configDict: [String: String] = [:] | ||
| for (key, value) in options { | ||
| if let strValue = value as? String { | ||
| configDict[key] = strValue | ||
| } | ||
| } | ||
| if let configData = try? JSONEncoder().encode(configDict) { | ||
| defaults?.set(configData, forKey: "LastVPNConfig") | ||
| defaults?.synchronize() | ||
| } | ||
|
|
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The VPN configuration persistence only saves String values from the options dictionary. However, the options dictionary also contains NSNumber values (like mtu) and NSArray values (like routes). These non-string values will be silently ignored, meaning the widget won't be able to restart the VPN with the exact same configuration. Consider either converting all option types to strings before encoding, or using a different serialization approach that preserves the type information.
| // Save config to App Group for Widget use | |
| let defaults = UserDefaults(suiteName: "group.site.yinmo.easytier") | |
| var configDict: [String: String] = [:] | |
| for (key, value) in options { | |
| if let strValue = value as? String { | |
| configDict[key] = strValue | |
| } | |
| } | |
| if let configData = try? JSONEncoder().encode(configDict) { | |
| defaults?.set(configData, forKey: "LastVPNConfig") | |
| defaults?.synchronize() | |
| } | |
| // Save full config (including non-string values) to App Group for widget use | |
| let defaults = UserDefaults(suiteName: "group.site.yinmo.easytier") | |
| defaults?.set(options, forKey: "LastVPNConfig") | |
| defaults?.synchronize() | |
| // Try to start with empty options as fallback | ||
| try manager.connection.startVPNTunnel() | ||
| return .result() |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the config data is not available in the App Group, the code falls back to starting the VPN tunnel with empty options. This will likely fail to establish a connection because the VPN tunnel requires configuration data (network name, secret, etc.). Consider throwing an error or returning early with a more descriptive error message instead of attempting to connect with empty options.
| // Try to start with empty options as fallback | |
| try manager.connection.startVPNTunnel() | |
| return .result() | |
| // Config is required to start the VPN tunnel; fail explicitly instead of using empty options. | |
| throw NSError( | |
| domain: "site.yinmo.easytier.ToggleVPNIntent", | |
| code: 1, | |
| userInfo: [ | |
| NSLocalizedDescriptionKey: "VPN configuration is not available. Please open EasyTier to configure the VPN before connecting from the widget." | |
| ] | |
| ) |
| @MainActor | ||
| func perform() async throws -> some IntentResult { | ||
| let profile = try getTargetProfile(network) | ||
| let manager = NEManager() | ||
| try await manager.load() | ||
| try await manager.connect(profile: profile) |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each shortcut intent creates a new instance of NEManager. While this works, it means the intents don't share state with the main app's NEManager instance. Consider whether this could lead to race conditions if a user triggers a shortcut while the app is also managing the VPN connection. The load() method fetches the current VPN manager state, so it should be mostly safe, but simultaneous operations could potentially conflict.
| Label(isOn ? "Connected" : "Disconnected", systemImage: "network") | ||
| .controlWidgetActionHint(isOn ? "Disconnect" : "Connect") |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The display strings "Connected", "Disconnected", "Connect", and "Disconnect" are hard-coded and not localized. These should use LocalizedStringResource to support the Chinese localization that exists elsewhere in the app.
| struct ToggleVPNIntent: SetValueIntent { | ||
| static let title: LocalizedStringResource = "Toggle VPN" | ||
|
|
||
| @Parameter(title: "Connected") |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter title "Connected" is hard-coded and not localized. This should use LocalizedStringResource to support the Chinese localization that exists elsewhere in the app.
| @Parameter(title: "Connected") | |
| @Parameter(title: LocalizedStringResource("Connected")) |
| attributes = { | ||
| BuildIndependentTargetsInParallel = 1; | ||
| LastSwiftUpdateCheck = 2620; | ||
| LastSwiftUpdateCheck = 2600; |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LastSwiftUpdateCheck was changed from 2620 to 2600. This appears to be a regression - it's going from Xcode 16.2.0 to Xcode 16.0.0. Unless there's a specific reason for this downgrade, it should remain at 2620 or be updated to match the current Xcode version being used.
| LastSwiftUpdateCheck = 2600; | |
| LastSwiftUpdateCheck = 2620; |
| func perform() async throws -> some IntentResult { | ||
| let managers = try await NETunnelProviderManager.loadAllFromPreferences() | ||
| guard let manager = managers.first else { | ||
| return .result() | ||
| } |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the shortcuts, ToggleVPNIntent creates a new NETunnelProviderManager instance on each invocation rather than reusing a shared instance. While this fetches the current state, simultaneous operations from the widget and the main app could potentially conflict when both try to manage the VPN connection state.
| .displayName("EasyTier") | ||
| .description("Toggle VPN connection") |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The display strings "EasyTier" and "Toggle VPN connection" are hard-coded and not localized. These should use LocalizedStringResource to support the Chinese localization that exists elsewhere in the app.
| } | ||
|
|
||
| struct ToggleVPNIntent: SetValueIntent { | ||
| static let title: LocalizedStringResource = "Toggle VPN" |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title "Toggle VPN" is hard-coded and not localized. This should use LocalizedStringResource to support the Chinese localization that exists elsewhere in the app.
| // Save config to App Group for Widget use | ||
| let defaults = UserDefaults(suiteName: "group.site.yinmo.easytier") | ||
| var configDict: [String: String] = [:] | ||
| for (key, value) in options { | ||
| if let strValue = value as? String { | ||
| configDict[key] = strValue | ||
| } | ||
| } | ||
| if let configData = try? JSONEncoder().encode(configDict) { | ||
| defaults?.set(configData, forKey: "LastVPNConfig") | ||
| defaults?.synchronize() | ||
| } |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code serializes the full VPN configuration (including values like NetworkConfig.networkIdentity.networkSecret inside the config string) and writes it in cleartext JSON into the shared app-group UserDefaults under the LastVPNConfig key. If any other app/extension with the same app-group entitlement or an attacker with filesystem access to the container is compromised, they can read this file and recover the network secret, allowing unauthorized devices to join the EasyTier network or clone this client. Consider avoiding persistence of the full config in shared preferences, instead storing only non-sensitive identifiers in the app group and keeping secrets in a more protected store (for example, the Keychain or NE-managed configuration only the tunnel provider can read).
|
@copilot 做好 i18n ,要求依从原项目的做法 |
|
@chenx-dust I've opened a new pull request, #5, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@copilot 变基到最新更改 |
|
@chenx-dust I've opened a new pull request, #6, to work on those changes. Once the pull request is ready, I'll request review from you. |
ref sing-box.
- Added localization keys to Localizable.xcstrings: - vpn_connected (已连接) - vpn_disconnected (已断开) - vpn_connect (连接) - vpn_disconnect (断开) - toggle_vpn (切换 VPN) - toggle_vpn_connection (切换 VPN 连接) - Updated ControlWidgetsControl.swift to use LocalizedStringResource Co-authored-by: chenx-dust <16610294+chenx-dust@users.noreply.github.com>
No description provided.