Skip to content
56 changes: 46 additions & 10 deletions NetBird.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@
50E608132A7958B100BAF09B /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E608122A7958B100BAF09B /* MainViewModel.swift */; };
50E608242A79966600BAF09B /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E608232A79966600BAF09B /* AboutView.swift */; };
50E608262A79968500BAF09B /* AdvancedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E608252A79968500BAF09B /* AdvancedView.swift */; };
55472AC52F59E3C000382947 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 55472AC42F59E3C000382947 /* GoogleService-Info.plist */; };
55472AC62F59E3C000382947 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 55472AC42F59E3C000382947 /* GoogleService-Info.plist */; };
55472AC72F59E3C000382947 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 55472AC42F59E3C000382947 /* GoogleService-Info.plist */; };
55472AC82F59E3C000382947 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 55472AC42F59E3C000382947 /* GoogleService-Info.plist */; };
5554ACC22F7E59700047BDAC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5554ACC12F7E59700047BDAC /* GoogleService-Info.plist */; };
5554ACC32F7E59700047BDAC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5554ACC12F7E59700047BDAC /* GoogleService-Info.plist */; };
5554ACC42F7E59700047BDAC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5554ACC12F7E59700047BDAC /* GoogleService-Info.plist */; };
5554ACC52F7E59700047BDAC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5554ACC12F7E59700047BDAC /* GoogleService-Info.plist */; };
55B5E81B2F39158200852AA7 /* InternetStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B5E81A2F39158200852AA7 /* InternetStatusView.swift */; };
55D865852F70982000A2EFF8 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D865842F70982000A2EFF8 /* WidgetKit.framework */; };
55D865872F70982000A2EFF8 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D865862F70982000A2EFF8 /* SwiftUI.framework */; };
Expand All @@ -162,6 +162,18 @@
A1C3D5EE2F000008001A2B3C /* CellularOnDemandPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C3D5E82F000002001A2B3C /* CellularOnDemandPolicy.swift */; };
A1C3D5EF2F000009001A2B3C /* CellularOnDemandPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C3D5E82F000002001A2B3C /* CellularOnDemandPolicy.swift */; };
A1C3D5F02F00000A001A2B3C /* CellularOnDemandPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C3D5E82F000002001A2B3C /* CellularOnDemandPolicy.swift */; };
AA0001012F22000100000001 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001002F22000100000001 /* ProfileManager.swift */; };
AA0001022F22000100000001 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001002F22000100000001 /* ProfileManager.swift */; };
AA0001032F22000100000001 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001002F22000100000001 /* ProfileManager.swift */; };
AA0001042F22000100000001 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001002F22000100000001 /* ProfileManager.swift */; };
AA0002052F22000200000001 /* ProfileBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0002012F22000200000001 /* ProfileBadge.swift */; };
AA0002062F22000200000001 /* ProfilesListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0002022F22000200000001 /* ProfilesListView.swift */; };
AA0002072F22000200000001 /* AddProfileSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0002032F22000200000001 /* AddProfileSheet.swift */; };
AA0002082F22000200000001 /* AddProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0002042F22000200000001 /* AddProfileViewModel.swift */; };
AA0009012F22000900000001 /* ProfileConnectionCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0009002F22000900000001 /* ProfileConnectionCache.swift */; };
AA0009022F22000900000001 /* ProfileConnectionCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0009002F22000900000001 /* ProfileConnectionCache.swift */; };
AA0009032F22000900000001 /* ProfileConnectionCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0009002F22000900000001 /* ProfileConnectionCache.swift */; };
AA0009042F22000900000001 /* ProfileConnectionCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0009002F22000900000001 /* ProfileConnectionCache.swift */; };
AA1B2C022F4E5A0100D1E2F3 /* TVGradientBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1B2C012F4E5A0100D1E2F3 /* TVGradientBackground.swift */; };
B1A2C3D42F3A000100000001 /* PeerDetailSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A2C3D32F3A000100000001 /* PeerDetailSheet.swift */; };
BB3D4E022F4E5A0200D1E2F3 /* TVPreSharedKeyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB3D4E012F4E5A0200D1E2F3 /* TVPreSharedKeyButton.swift */; };
Expand Down Expand Up @@ -325,7 +337,7 @@
50E608232A79966600BAF09B /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
50E608252A79968500BAF09B /* AdvancedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedView.swift; sourceTree = "<group>"; };
53CB9305A9DC6CAD1895495A /* SharedUserDefaultsTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SharedUserDefaultsTests.swift; sourceTree = "<group>"; };
55472AC42F59E3C000382947 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
5554ACC12F7E59700047BDAC /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
55B5E81A2F39158200852AA7 /* InternetStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetStatusView.swift; sourceTree = "<group>"; };
55D865832F70982000A2EFF8 /* NetBirdWidgetExtensionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NetBirdWidgetExtensionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
55D865842F70982000A2EFF8 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
Expand All @@ -339,6 +351,12 @@
A1B2C3D42EEDF500001A2B3C /* ConfigurationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationProvider.swift; sourceTree = "<group>"; };
A1C3D5E72F000001001A2B3C /* WiFiOnDemandPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WiFiOnDemandPolicy.swift; sourceTree = "<group>"; };
A1C3D5E82F000002001A2B3C /* CellularOnDemandPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellularOnDemandPolicy.swift; sourceTree = "<group>"; };
AA0001002F22000100000001 /* ProfileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileManager.swift; sourceTree = "<group>"; };
AA0002012F22000200000001 /* ProfileBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileBadge.swift; sourceTree = "<group>"; };
AA0002022F22000200000001 /* ProfilesListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilesListView.swift; sourceTree = "<group>"; };
AA0002032F22000200000001 /* AddProfileSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProfileSheet.swift; sourceTree = "<group>"; };
AA0002042F22000200000001 /* AddProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProfileViewModel.swift; sourceTree = "<group>"; };
AA0009002F22000900000001 /* ProfileConnectionCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileConnectionCache.swift; sourceTree = "<group>"; };
AA1B2C012F4E5A0100D1E2F3 /* TVGradientBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVGradientBackground.swift; sourceTree = "<group>"; };
B1A2C3D32F3A000100000001 /* PeerDetailSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerDetailSheet.swift; sourceTree = "<group>"; };
BB3D4E012F4E5A0200D1E2F3 /* TVPreSharedKeyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVPreSharedKeyButton.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -531,7 +549,7 @@
50A8910E2A792A15007C48FC = {
isa = PBXGroup;
children = (
55472AC42F59E3C000382947 /* GoogleService-Info.plist */,
5554ACC12F7E59700047BDAC /* GoogleService-Info.plist */,
50D402932BD9143900D4AC5B /* NetBirdSDK.xcframework */,
50245A0A2A7AA9390034792B /* NetBird-Bridging-Header.h */,
50A891192A792A15007C48FC /* NetBird */,
Expand Down Expand Up @@ -580,6 +598,8 @@
A1C3D5E82F000002001A2B3C /* CellularOnDemandPolicy.swift */,
F1B292062EE0AC25001D91B8 /* EnvVarPackager.swift */,
50245A292A7BDB590034792B /* Preferences.swift */,
AA0001002F22000100000001 /* ProfileManager.swift */,
AA0009002F22000900000001 /* ProfileConnectionCache.swift */,
A1B2C3D42EEDF500001A2B3C /* ConfigurationProvider.swift */,
50245A2D2A7BDC470034792B /* NetworkChangeListener.swift */,
50CD81612AD0595E00CF830B /* DNSManager.swift */,
Expand Down Expand Up @@ -615,6 +635,7 @@
50E608122A7958B100BAF09B /* MainViewModel.swift */,
50D402962BD9B89300D4AC5B /* PeerViewModel.swift */,
509CCD692BE908C000B7C2D8 /* RoutesViewModel.swift */,
AA0002042F22000200000001 /* AddProfileViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -674,6 +695,9 @@
42873052F9544A89B1408339 /* iOSPeersView.swift */,
C7A1CFF65CC44187912007EC /* iOSNetworksView.swift */,
2F8A4B98A775451786C5DDF8 /* iOSSettingsView.swift */,
AA0002012F22000200000001 /* ProfileBadge.swift */,
AA0002022F22000200000001 /* ProfilesListView.swift */,
AA0002032F22000200000001 /* AddProfileSheet.swift */,
9CD257EF78F038560FF3112D /* VPNOnDemandView.swift */,
5BFDF94163AF4C32A44DB3CD /* FirstLaunchView.swift */,
);
Expand Down Expand Up @@ -889,15 +913,15 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
55472AC52F59E3C000382947 /* GoogleService-Info.plist in Resources */,
5554ACC42F7E59700047BDAC /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
441C5AFB2EDF0DD20055EEFC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
55472AC82F59E3C000382947 /* GoogleService-Info.plist in Resources */,
5554ACC32F7E59700047BDAC /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -907,7 +931,7 @@
files = (
501B0DCE2AE04DDE004BE7A7 /* button-disconnecting.json in Resources */,
501B0DD22AE04DDE004BE7A7 /* logo_NetBird.json in Resources */,
55472AC62F59E3C000382947 /* GoogleService-Info.plist in Resources */,
5554ACC22F7E59700047BDAC /* GoogleService-Info.plist in Resources */,
501B0DDC2AE04DDE004BE7A7 /* button-connected.json in Resources */,
501B0DD62AE04DDE004BE7A7 /* button-start-connecting.json in Resources */,
501B0DDA2AE04DDE004BE7A7 /* button-full.json in Resources */,
Expand All @@ -929,7 +953,7 @@
501B0DCD2AE04DDE004BE7A7 /* button-disconnecting.json in Resources */,
501B0DD12AE04DDE004BE7A7 /* logo_NetBird.json in Resources */,
501B0DDB2AE04DDE004BE7A7 /* button-connected.json in Resources */,
55472AC72F59E3C000382947 /* GoogleService-Info.plist in Resources */,
5554ACC52F7E59700047BDAC /* GoogleService-Info.plist in Resources */,
501B0DCF2AE04DDE004BE7A7 /* button-connecting-loop.json in Resources */,
501B0DD72AE04DDE004BE7A7 /* button-full2.json in Resources */,
);
Expand Down Expand Up @@ -1009,6 +1033,8 @@
445B5F762EECAF02008932B8 /* EnvVarPackager.swift in Sources */,
443782D02EDF29A800F9FA94 /* Device.swift in Sources */,
443782D12EDF29A800F9FA94 /* Preferences.swift in Sources */,
AA0001012F22000100000001 /* ProfileManager.swift in Sources */,
AA0009012F22000900000001 /* ProfileConnectionCache.swift in Sources */,
A1B2C3D52EEDF501001A2B3C /* ConfigurationProvider.swift in Sources */,
443782D42EDF29A800F9FA94 /* RoutesSelectionDetails.swift in Sources */,
443782D52EDF29A800F9FA94 /* StatusDetails.swift in Sources */,
Expand Down Expand Up @@ -1051,6 +1077,8 @@
44F3E3902EE2151100C87FEC /* StatusDetails.swift in Sources */,
44F3E3912EE2151100C87FEC /* ClientState.swift in Sources */,
44F3E3922EE2151100C87FEC /* Preferences.swift in Sources */,
AA0001022F22000100000001 /* ProfileManager.swift in Sources */,
AA0009022F22000900000001 /* ProfileConnectionCache.swift in Sources */,
A1B2C3D72EEDF503001A2B3C /* ConfigurationProvider.swift in Sources */,
44F3E3932EE2151100C87FEC /* NetworkExtensionAdapter.swift in Sources */,
44F3E3942EE2151100C87FEC /* ConnectionListener.swift in Sources */,
Expand All @@ -1069,6 +1097,8 @@
50245A572A80431C0034792B /* PacketTunnelProvider.swift in Sources */,
505118D12AD96ECA003027D3 /* key.c in Sources */,
50213A2D2A8D0AA30031D993 /* Preferences.swift in Sources */,
AA0001032F22000100000001 /* ProfileManager.swift in Sources */,
AA0009032F22000900000001 /* ProfileConnectionCache.swift in Sources */,
50CD81A82AD5504B00CF830B /* StatusDetails.swift in Sources */,
F1B2920B2EE0BC46001D91B8 /* GlobalConstants.swift in Sources */,
A1C3D5EB2F000005001A2B3C /* WiFiOnDemandPolicy.swift in Sources */,
Expand Down Expand Up @@ -1119,6 +1149,8 @@
50E608242A79966600BAF09B /* AboutView.swift in Sources */,
50CD81622AD0595E00CF830B /* DNSManager.swift in Sources */,
50216D892ACB18EE009574C9 /* Preferences.swift in Sources */,
AA0001042F22000100000001 /* ProfileManager.swift in Sources */,
AA0009042F22000900000001 /* ProfileConnectionCache.swift in Sources */,
A1B2C3D62EEDF502001A2B3C /* ConfigurationProvider.swift in Sources */,
50CD81B02AD5B94D00CF830B /* PeerCard.swift in Sources */,
B1A2C3D42F3A000100000001 /* PeerDetailSheet.swift in Sources */,
Expand All @@ -1134,6 +1166,10 @@
962925F1DAA24D40B98D395B /* iOSPeersView.swift in Sources */,
71DD928A21BE4943BB0FEC1D /* iOSNetworksView.swift in Sources */,
0C71C019350D42AB8F110336 /* iOSSettingsView.swift in Sources */,
AA0002052F22000200000001 /* ProfileBadge.swift in Sources */,
AA0002062F22000200000001 /* ProfilesListView.swift in Sources */,
AA0002072F22000200000001 /* AddProfileSheet.swift in Sources */,
AA0002082F22000200000001 /* AddProfileViewModel.swift in Sources */,
4849965EC2515950756C8F10 /* VPNOnDemandView.swift in Sources */,
F2DCB2437ECA42C3AEC3C895 /* FirstLaunchView.swift in Sources */,
);
Expand Down
83 changes: 83 additions & 0 deletions NetBird/Source/App/ViewModels/AddProfileViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// AddProfileViewModel.swift
// NetBird
//

import Foundation

#if os(iOS)

@MainActor
class AddProfileViewModel: ObservableObject {
@Published var isLoading = false
@Published var isSuccess = false
@Published var profileError: String?
@Published var urlError: String?
@Published var setupKeyError: String?
@Published var generalError: String?
@Published var ssoNotSupportedError: String?

private let defaultManagementServerUrl = "https://api.netbird.io"

func create(name: String, serverUrl: String, setupKey: String) {
clearErrors()

// 1. Create profile directory
do {
try ProfileManager.shared.addProfile(name)
} catch {
profileError = error.localizedDescription
return
}

// 2. Get config path for the new profile
guard let configPath = ProfileManager.shared.configPath(for: name) else {
profileError = "Unable to access profile directory"
try? ProfileManager.shared.removeProfile(name)
return
}

// 3. Configure the management server for this profile
let serverVM = ServerViewModel(configurationFilePath: configPath, deviceName: Device.getName())
let trimmed = serverUrl.trimmingCharacters(in: .whitespacesAndNewlines)
var urlComponents = URLComponents(string: trimmed)
if let scheme = urlComponents?.scheme { urlComponents?.scheme = scheme.lowercased() }
if let host = urlComponents?.host { urlComponents?.host = host.lowercased() }
let trimmedUrl = urlComponents?.string ?? trimmed
let finalUrl = trimmedUrl.isEmpty ? defaultManagementServerUrl : trimmedUrl
let key = setupKey.trimmingCharacters(in: .whitespacesAndNewlines)

isLoading = true

Task {
if !key.isEmpty {
await serverVM.loginWithSetupKey(managementServerUrl: finalUrl, setupKey: key)
} else {
await serverVM.changeManagementServerAddress(managementServerUrl: finalUrl)
}

isLoading = false

if serverVM.isOperationSuccessful {
isSuccess = true
} else {
// Surface errors and rollback profile creation
urlError = serverVM.viewErrors.urlError
setupKeyError = serverVM.viewErrors.setupKeyError
generalError = serverVM.viewErrors.generalError
ssoNotSupportedError = serverVM.viewErrors.ssoNotSupportedError
try? ProfileManager.shared.removeProfile(name)
}
}
}

func clearErrors() {
profileError = nil
urlError = nil
setupKeyError = nil
generalError = nil
ssoNotSupportedError = nil
}
}

#endif
Loading
Loading