Skip to content

Conversation

@YinMo19
Copy link
Collaborator

@YinMo19 YinMo19 commented Jan 13, 2026

No description provided.

@YinMo19 YinMo19 requested a review from Copilot January 13, 2026 09:51
Copy link

Copilot AI left a 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.

@YinMo19 YinMo19 requested a review from Copilot January 13, 2026 09:51
Copy link

Copilot AI left a 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.

Copy link

Copilot AI left a 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.

Comment on lines 176 to 188
// 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()
}

Copy link

Copilot AI Jan 13, 2026

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.

Suggested change
// 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()

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +63
// Try to start with empty options as fallback
try manager.connection.startVPNTunnel()
return .result()
Copy link

Copilot AI Jan 13, 2026

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.

Suggested change
// 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."
]
)

Copilot uses AI. Check for mistakes.
Comment on lines +94 to +99
@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)
Copy link

Copilot AI Jan 13, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines 26 to 27
Label(isOn ? "Connected" : "Disconnected", systemImage: "network")
.controlWidgetActionHint(isOn ? "Disconnect" : "Connect")
Copy link

Copilot AI Jan 13, 2026

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.

Copilot uses AI. Check for mistakes.
struct ToggleVPNIntent: SetValueIntent {
static let title: LocalizedStringResource = "Toggle VPN"

@Parameter(title: "Connected")
Copy link

Copilot AI Jan 13, 2026

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.

Suggested change
@Parameter(title: "Connected")
@Parameter(title: LocalizedStringResource("Connected"))

Copilot uses AI. Check for mistakes.
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 2620;
LastSwiftUpdateCheck = 2600;
Copy link

Copilot AI Jan 13, 2026

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.

Suggested change
LastSwiftUpdateCheck = 2600;
LastSwiftUpdateCheck = 2620;

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +54
func perform() async throws -> some IntentResult {
let managers = try await NETunnelProviderManager.loadAllFromPreferences()
guard let manager = managers.first else {
return .result()
}
Copy link

Copilot AI Jan 13, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines 30 to 31
.displayName("EasyTier")
.description("Toggle VPN connection")
Copy link

Copilot AI Jan 13, 2026

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.

Copilot uses AI. Check for mistakes.
}

struct ToggleVPNIntent: SetValueIntent {
static let title: LocalizedStringResource = "Toggle VPN"
Copy link

Copilot AI Jan 13, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +209
// 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()
}
Copy link

Copilot AI Jan 13, 2026

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 uses AI. Check for mistakes.
@chenx-dust
Copy link
Collaborator

@copilot 做好 i18n ,要求依从原项目的做法

Copy link
Contributor

Copilot AI commented Jan 14, 2026

@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.

@chenx-dust
Copy link
Collaborator

@copilot 变基到最新更改

Copy link
Contributor

Copilot AI commented Jan 14, 2026

@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.

YinMo19 and others added 7 commits January 14, 2026 13:35
- 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>
@chenx-dust chenx-dust merged commit 88d69cf into main Jan 14, 2026
1 check was pending
@chenx-dust chenx-dust deleted the shortcuts branch January 14, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants