You've already forked ios-client
mirror of
https://github.com/netbirdio/ios-client.git
synced 2026-05-22 17:10:12 -07:00
0327624b30
* fix layout on ipad * Create multi profiles * multi-profile server config, connection cache, and auth fixes Split ProfilesView into ProfilesListView, AddProfileSheet, ProfileBadge, AddProfileViewModel - Add server URL + setup key fields to Add Profile screen - Store per-profile connection data (ip/fqdn/managementURL) as typed model in ProfileConnectionCache - Show cached connection info immediately on profile switch; empty if no prior data - Fix profile deletion persistence via tombstone in profiles.json - Fix logout to remove both netbird.cfg and state.json (cfg holds auth tokens) - Preserve managementURL in UI after logout via cache fallback - Guard polling from overwriting new profile's data during disconnect/reconnect cycle * fix(multi-profile): reinitialize VPN adapter on profile switch and show current server URL * Update project.pbxproj * fix(multi-profile): prevent default server overwrite on logout/re-login * Update PacketTunnelProvider.swift * fix(multi-profile): address code review findings - Normalize only scheme and host to lowercase when saving management server URL; previously the full URL was lowercased which could corrupt case-sensitive paths on self-hosted servers - Move switchConnectionInfo(to:) inside the do-block so the connection UI is only updated after a successful profile switch - Add ProfileConnectionCache.remove(for:) and clearConnectionData(for:) to prevent stale ip/fqdn/managementURL from persisting after a profile is deleted or logged out; call them from removeProfile and logoutProfile - Use ASWebAuthenticationSession.Callback.customScheme on iOS 17.4+, falling back to the deprecated callbackURLScheme initializer on older versions; add a comment explaining why "http" is used and that a proper fix requires custom-scheme support in the SDK - Guard presentationAnchor against a missing key window with assertionFailure in debug builds instead of silently returning an empty UIWindow
91 lines
2.5 KiB
Swift
91 lines
2.5 KiB
Swift
//
|
|
// ProfileConnectionCache.swift
|
|
// NetBird
|
|
//
|
|
|
|
import Foundation
|
|
|
|
// MARK: - Model
|
|
|
|
struct ProfileConnectionEntry: Codable, Equatable {
|
|
var ip: String
|
|
var fqdn: String
|
|
var managementURL: String?
|
|
}
|
|
|
|
// MARK: - Cache
|
|
|
|
/// Stores and retrieves last-known connection data (ip/fqdn/managementURL) per profile.
|
|
/// Persisted as a JSON-encoded dictionary under a single UserDefaults key.
|
|
struct ProfileConnectionCache {
|
|
|
|
private static let storageKey = "netbird_profiles_connection_data"
|
|
private let defaults: UserDefaults
|
|
|
|
init(defaults: UserDefaults = .standard) {
|
|
self.defaults = defaults
|
|
}
|
|
|
|
// MARK: - Read
|
|
|
|
func entry(for profile: String) -> ProfileConnectionEntry? {
|
|
return load()[profile]
|
|
}
|
|
|
|
func managementURL(for profile: String) -> String? {
|
|
return load()[profile]?.managementURL
|
|
}
|
|
|
|
// MARK: - Write
|
|
|
|
func save(ip: String, fqdn: String, for profile: String) {
|
|
var all = load()
|
|
var entry = all[profile] ?? ProfileConnectionEntry(ip: "", fqdn: "", managementURL: nil)
|
|
entry.ip = ip
|
|
entry.fqdn = fqdn
|
|
all[profile] = entry
|
|
persist(all)
|
|
}
|
|
|
|
func saveManagementURL(_ url: String, for profile: String) {
|
|
var all = load()
|
|
var entry = all[profile] ?? ProfileConnectionEntry(ip: "", fqdn: "", managementURL: nil)
|
|
entry.managementURL = url
|
|
all[profile] = entry
|
|
persist(all)
|
|
}
|
|
|
|
/// Clears ip/fqdn for a profile after logout, preserving managementURL for re-login.
|
|
func clearConnectionData(for profile: String) {
|
|
var all = load()
|
|
guard var entry = all[profile] else { return }
|
|
entry.ip = ""
|
|
entry.fqdn = ""
|
|
all[profile] = entry
|
|
persist(all)
|
|
}
|
|
|
|
/// Removes all cached data for a deleted profile.
|
|
func remove(for profile: String) {
|
|
var all = load()
|
|
guard all[profile] != nil else { return }
|
|
all.removeValue(forKey: profile)
|
|
persist(all)
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func load() -> [String: ProfileConnectionEntry] {
|
|
guard
|
|
let data = defaults.data(forKey: Self.storageKey),
|
|
let decoded = try? JSONDecoder().decode([String: ProfileConnectionEntry].self, from: data)
|
|
else { return [:] }
|
|
return decoded
|
|
}
|
|
|
|
private func persist(_ entries: [String: ProfileConnectionEntry]) {
|
|
guard let data = try? JSONEncoder().encode(entries) else { return }
|
|
defaults.set(data, forKey: Self.storageKey)
|
|
}
|
|
}
|