Skip to content

Commit 072e62c

Browse files
BIT-2410: Support managed app config environment URLs (#731)
1 parent 29cc027 commit 072e62c

File tree

2 files changed

+87
-4
lines changed

2 files changed

+87
-4
lines changed

BitwardenShared/Core/Platform/Services/EnvironmentService.swift

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,21 @@ class DefaultEnvironmentService: EnvironmentService {
6868
/// The app's current environment URLs.
6969
private var environmentUrls: EnvironmentUrls
7070

71+
/// The shared UserDefaults instance (NOTE: this should be the standard one just for the app,
72+
/// not one in the app group).
73+
private let standardUserDefaults: UserDefaults
74+
7175
// MARK: Initialization
7276

7377
/// Initialize a `DefaultEnvironmentService`.
7478
///
75-
/// - Parameter stateService: The service used by the application to manage account state.
79+
/// - Parameters:
80+
/// - stateService: The service used by the application to manage account state.
81+
/// - standardUserDefaults: The shared UserDefaults instance.
7682
///
77-
init(stateService: StateService) {
83+
init(stateService: StateService, standardUserDefaults: UserDefaults = .standard) {
7884
self.stateService = stateService
85+
self.standardUserDefaults = standardUserDefaults
7986

8087
environmentUrls = EnvironmentUrls(environmentUrlData: .defaultUS)
8188
}
@@ -84,14 +91,18 @@ class DefaultEnvironmentService: EnvironmentService {
8491

8592
func loadURLsForActiveAccount() async {
8693
let urls: EnvironmentUrlData
94+
let managedSettingsUrls = managedSettingsUrls()
8795
if let environmentUrls = try? await stateService.getEnvironmentUrls() {
8896
urls = environmentUrls
97+
} else if let managedSettingsUrls {
98+
urls = managedSettingsUrls
8999
} else if let preAuthUrls = await stateService.getPreAuthEnvironmentUrls() {
90100
urls = preAuthUrls
91101
} else {
92102
urls = .defaultUS
93103
}
94-
await setPreAuthURLs(urls: urls)
104+
105+
await setPreAuthURLs(urls: managedSettingsUrls ?? urls)
95106
environmentUrls = EnvironmentUrls(environmentUrlData: urls)
96107

97108
// swiftformat:disable:next redundantSelf
@@ -105,6 +116,22 @@ class DefaultEnvironmentService: EnvironmentService {
105116
// swiftformat:disable:next redundantSelf
106117
Logger.application.info("Setting pre-auth URLs: \(String(describing: self.environmentUrls))")
107118
}
119+
120+
// MARK: Private
121+
122+
/// Returns the URLs that are specified as part of a managed app configuration.
123+
///
124+
/// - Returns: The environment URLs that are specified as part of a managed app configuration.
125+
///
126+
private func managedSettingsUrls() -> EnvironmentUrlData? {
127+
let managedSettings = standardUserDefaults.dictionary(forKey: "com.apple.configuration.managed")
128+
guard let baseUrlString = managedSettings?["baseEnvironmentUrl"] as? String,
129+
let baseUrl = URL(string: baseUrlString)
130+
else {
131+
return nil
132+
}
133+
return EnvironmentUrlData(base: baseUrl)
134+
}
108135
}
109136

110137
extension DefaultEnvironmentService {

BitwardenShared/Core/Platform/Services/EnvironmentServiceTests.swift

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class EnvironmentServiceTests: XCTestCase {
66
// MARK: Properties
77

88
var stateService: MockStateService!
9+
var standardUserDefaults: UserDefaults!
910
var subject: EnvironmentService!
1011

1112
// MARK: Setup & Teardown
@@ -14,14 +15,20 @@ class EnvironmentServiceTests: XCTestCase {
1415
super.setUp()
1516

1617
stateService = MockStateService()
18+
standardUserDefaults = UserDefaults(suiteName: "test")
19+
standardUserDefaults.removeObject(forKey: "com.apple.configuration.managed")
1720

18-
subject = DefaultEnvironmentService(stateService: stateService)
21+
subject = DefaultEnvironmentService(
22+
stateService: stateService,
23+
standardUserDefaults: standardUserDefaults
24+
)
1925
}
2026

2127
override func tearDown() {
2228
super.tearDown()
2329

2430
stateService = nil
31+
standardUserDefaults = nil
2532
subject = nil
2633
}
2734

@@ -82,6 +89,55 @@ class EnvironmentServiceTests: XCTestCase {
8289
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
8390
}
8491

92+
/// `loadURLsForActiveAccount()` loads the managed config URLs.
93+
func test_loadURLsForActiveAccount_managedConfig() async throws {
94+
standardUserDefaults.setValue(
95+
["baseEnvironmentUrl": "https://vault.example.com"],
96+
forKey: "com.apple.configuration.managed"
97+
)
98+
99+
await subject.loadURLsForActiveAccount()
100+
101+
let urls = try EnvironmentUrlData(base: XCTUnwrap(URL(string: "https://vault.example.com")))
102+
XCTAssertEqual(subject.apiURL, URL(string: "https://vault.example.com/api"))
103+
XCTAssertEqual(subject.eventsURL, URL(string: "https://vault.example.com/events"))
104+
XCTAssertEqual(subject.iconsURL, URL(string: "https://vault.example.com/icons"))
105+
XCTAssertEqual(subject.identityURL, URL(string: "https://vault.example.com/identity"))
106+
XCTAssertEqual(subject.importItemsURL, URL(string: "https://vault.example.com/#/tools/import"))
107+
XCTAssertEqual(subject.region, .selfHosted)
108+
XCTAssertEqual(subject.sendShareURL, URL(string: "https://vault.example.com/#/send"))
109+
XCTAssertEqual(subject.settingsURL, URL(string: "https://vault.example.com/#/settings"))
110+
XCTAssertEqual(subject.webVaultURL, URL(string: "https://vault.example.com"))
111+
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
112+
}
113+
114+
/// `loadURLsForActiveAccount()` doesn't load the managed config URLs if there's an active
115+
/// account, but sets the pre-auth URLs to the managed config URLs.
116+
func test_loadURLsForActiveAccount_managedConfigActiveAccount() async throws {
117+
let account = Account.fixture()
118+
stateService.activeAccount = account
119+
stateService.environmentUrls[account.profile.userId] = .defaultUS
120+
standardUserDefaults.setValue(
121+
["baseEnvironmentUrl": "https://vault.example.com"],
122+
forKey: "com.apple.configuration.managed"
123+
)
124+
125+
await subject.loadURLsForActiveAccount()
126+
127+
XCTAssertEqual(subject.apiURL, URL(string: "https://vault.bitwarden.com/api"))
128+
XCTAssertEqual(subject.eventsURL, URL(string: "https://vault.bitwarden.com/events"))
129+
XCTAssertEqual(subject.iconsURL, URL(string: "https://vault.bitwarden.com/icons"))
130+
XCTAssertEqual(subject.identityURL, URL(string: "https://vault.bitwarden.com/identity"))
131+
XCTAssertEqual(subject.importItemsURL, URL(string: "https://vault.bitwarden.com/#/tools/import"))
132+
XCTAssertEqual(subject.region, .unitedStates)
133+
XCTAssertEqual(subject.sendShareURL, URL(string: "https://vault.bitwarden.com/#/send"))
134+
XCTAssertEqual(subject.settingsURL, URL(string: "https://vault.bitwarden.com/#/settings"))
135+
XCTAssertEqual(subject.webVaultURL, URL(string: "https://vault.bitwarden.com"))
136+
137+
let urls = try EnvironmentUrlData(base: XCTUnwrap(URL(string: "https://vault.example.com")))
138+
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
139+
}
140+
85141
/// `loadURLsForActiveAccount()` loads the default URLs if there's no active account
86142
/// and no preauth URLs.
87143
func test_loadURLsForActiveAccount_noAccount() async {

0 commit comments

Comments
 (0)