// /* * Copyright (c) 2021 BWI GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import Foundation let configKey = "com.apple.configuration.managed" extension UserDefaults { @objc dynamic var appConfigData: Dictionary? { get { return dictionary(forKey: configKey) } set { set(newValue, forKey: configKey) } } } @objcMembers class AppConfigService : NSObject { static let shared = AppConfigService() private let serverUrlKey = "home_server_url" private let contentScannerKey = "contentScanner" private let pusherUrlKey = "pusherUrl" private let permalinkUrlKey = "permalinkUrl" private let externalUrlSchemeKey = "external_url_scheme" private let savedConfig = "savedAppConfig" var appConfig = AppConfig() var completion: ((Bool, String) -> Void)? var configObserver: NSKeyValueObservation! var session: MXSession? var isAppConfig: Bool var lastDictionary: [String: Any]? private func loadAppConfig() { isAppConfig = false do { if let dataIn = UserDefaults.standard.value(forKey: savedConfig) as? Data { appConfig = try JSONDecoder().decode(AppConfig.self, from: dataIn) isAppConfig = true } } catch { } } private func saveAppConfig() { do { let dataOut = try JSONEncoder().encode(appConfig) UserDefaults.standard.setValue(dataOut, forKey: savedConfig) } catch { } } private func checkUrlSavety(_ serverUrl: String) async -> Bool { if BWIBuildSettings.shared.bwiEnableLoginProtection { let protectionService = LoginProtectionService() protectionService.hashes = BWIBuildSettings.shared.bwiHashes return await protectionService.isValid(serverUrl) } else { return true } } override init() { isAppConfig = false super.init() self.loadAppConfig() } deinit { NotificationCenter.default.removeObserver(self) } private func isSameConfig( dict: [String: Any]) -> Bool { if let lastDictionary = lastDictionary { if lastDictionary.count != dict.count { return false } if let newURl = dict[serverUrlKey] as? String, let oldURL = lastDictionary[serverUrlKey] as? String, newURl == oldURL { return true } } return false } func registerForAppConfig() { NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: OperationQueue.main) { [self] (note) in Task { await handleAppConfig() } } } func handleAppConfig() async { if let dict = UserDefaults.standard.dictionary(forKey: configKey) { // only compute if serverURL has not changed (this may need to be changed on Adminportal integration if !isSameConfig(dict: dict) { var config = AppConfig() if let serverUrl = dict[serverUrlKey] as? String { if serverUrl.count == 0 { config.serverUrl = nil } else if await checkUrlSavety(serverUrl) { config.serverUrl = serverUrl } } if let contentScannerUrl = dict[contentScannerKey] as? String { if await checkUrlSavety(contentScannerUrl) { config.contentScannerUrl = contentScannerUrl } } if let pusherUrl = dict[pusherUrlKey] as? String { if await checkUrlSavety(pusherUrl) { config.pusherUrl = pusherUrl } } if let permalinkUrl = dict[permalinkUrlKey] as? String { if await checkUrlSavety(permalinkUrl) { config.permalinkUrl = permalinkUrl } } if let externalUrlScheme = dict[externalUrlSchemeKey] as? String { config.externalUrlScheme = externalUrlScheme } // app config needs at least a valid server url if let serverUrl = config.serverUrl { isAppConfig = true appConfig = config lastDictionary = dict self.saveAppConfig() if let completion = self.completion { completion(true, serverUrl) } } } } } func resetConfig() { appConfig = AppConfig() self.saveAppConfig() } func serverUrl() -> String { if let url = appConfig.serverUrl { return url } else if let url = ServerURLHelper.shared.serverUrl() { return url } else if let session = session, let restClient = session.matrixRestClient { return restClient.homeserver } else { return BWIBuildSettings.shared.serverConfigDefaultHomeserverUrlString } } func pusherUrl() -> String { if let url = appConfig.pusherUrl { return url } else { return BWIBuildSettings.shared.serverConfigSygnalAPIUrlString } } func permalinkUrl() -> String? { ServerURLHelper.shared.selectedIndex = ServerURLHelper.shared.indexOf(self.serverUrl()) if let url = appConfig.permalinkUrl { return "https://" + url } else if let url = ServerURLHelper.shared.httpsPermalink() { return url } else { return BWIBuildSettings.shared.clientPermalinkBaseUrl } } func permalinkHost() -> String? { if let permalinkURL = URL(string: permalinkUrl() ?? "") { return permalinkURL.host } return "" } func externalUrlScheme() -> String? { return appConfig.externalUrlScheme } }