Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion Core/Core/Features/Login/LoginFindSchoolViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,10 @@ class LoginFindSchoolViewController: UIViewController {
host = host.lowercased()

// For manual oauth logins we trust the developer and don't modify the host.
if method != .manualOAuthLogin, !host.contains(".") {
if method != .manualOAuthLogin, !host.contains("."), env.app != .horizon {
host = "\(host).instructure.com"
} else if env.app == .horizon {
host = replaceRootDomain(urlString: host, newRootDomain: "instructure.com") ?? ""
}

searchField.resignFirstResponder()
Expand All @@ -157,6 +159,32 @@ class LoginFindSchoolViewController: UIViewController {
showLoginForHost(host)
}

func replaceRootDomain(urlString: String, newRootDomain: String) -> String? {
let urlWithScheme = "https://\(urlString)"

guard let url = URL(string: urlWithScheme) else {
return nil
}

// Try to extract host, fallback to raw string if needed
let host = url.host ?? urlString
let parts = host.components(separatedBy: ".")

let subdomain: String
if parts.count >= 3 {
// Full domain with subdomain (subdomain.domain.com
subdomain = parts.dropLast(2).joined(separator: ".")
} else if parts.count == 1 {
// Only a subdomain was typed (subdomain)
subdomain = parts[0]
} else {
subdomain = parts.dropLast().joined(separator: ".")
}

let newHost = "\(subdomain).\(newRootDomain)"
return newHost
}

private func toggleNextButtonVisibility() {
if let host = searchField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !host.isEmpty {
nextButton.accessibilityIdentifier = "nextButton"
Expand Down
59 changes: 59 additions & 0 deletions Horizon/Horizon/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import Combine
import Core
import Firebase
import HorizonUI
import UIKit

Expand All @@ -44,6 +45,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, AppEnvironmentDelegate {
_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// MARK: - Firebase

setupFirebase()

// MARK: Root view

window = UIWindow()
Expand Down Expand Up @@ -122,3 +127,57 @@ extension AppDelegate: Core.AnalyticsHandler {
analyticsTracker.endSession()
}
}

// MARK: - Crashlytics

extension AppDelegate {
@objc func setupFirebase() {
guard !testing else {
setupDebugCrashLogging()
return
}

if FirebaseOptions.defaultOptions()?.apiKey != nil {
FirebaseApp.configure()
configureRemoteConfig()
Core.Analytics.shared.handler = self
RemoteLogger.shared.handler = self
}
}

func setupDebugCrashLogging() {
NSSetUncaughtExceptionHandler { exception in
print("CRASH: \(exception)")
print("Stack Trace:")
for symbol in exception.callStackSymbols {
print(" \(symbol)")
}
}
}

func configureRemoteConfig() {
let remoteConfig = RemoteConfig.remoteConfig()
remoteConfig.fetch(withExpirationDuration: 0) { _, _ in
remoteConfig.activate { _, _ in
let keys = remoteConfig.allKeys(from: .remote)
for key in keys {
guard let feature = ExperimentalFeature(rawValue: key) else { continue }
let value = remoteConfig.configValue(forKey: key).boolValue
feature.isEnabled = value
Firebase.Crashlytics.crashlytics().setCustomValue(value, forKey: feature.userDefaultsKey)
}
}
}
}
}

extension AppDelegate: RemoteLogHandler {
func handleBreadcrumb(_ name: String) {
Firebase.Crashlytics.crashlytics().log(name)
}

func handleError(_ name: String, reason: String) {
let model = ExceptionModel(name: name, reason: reason)
Firebase.Crashlytics.crashlytics().record(exceptionModel: model)
}
}