diff --git a/AmahiAnywhere/AmahiAnywhere.xcodeproj/project.pbxproj b/AmahiAnywhere/AmahiAnywhere.xcodeproj/project.pbxproj index 0097eb7938f..04e3cba6ed0 100644 --- a/AmahiAnywhere/AmahiAnywhere.xcodeproj/project.pbxproj +++ b/AmahiAnywhere/AmahiAnywhere.xcodeproj/project.pbxproj @@ -70,6 +70,9 @@ 46657183205085FC000E0D45 /* FilesPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46657182205085FC000E0D45 /* FilesPresenter.swift */; }; 46CB896B204FB0FC0031151F /* SharesPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CB896A204FB0FC0031151F /* SharesPresenter.swift */; }; 46F87397204CC69500F1AF37 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F87396204CC69500F1AF37 /* Server.swift */; }; + 7229DB3824EA9A490081AEF9 /* HACModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7229DB3724EA9A490081AEF9 /* HACModel.swift */; }; + 7229DB3A24EAF4700081AEF9 /* NAULoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7229DB3924EAF4700081AEF9 /* NAULoginController.swift */; }; + 7229DB4324EB303A0081AEF9 /* WifiGatewayIP.m in Sources */ = {isa = PBXBuildFile; fileRef = 7229DB4224EB303A0081AEF9 /* WifiGatewayIP.m */; }; 7253F21824BDA89F0094C385 /* AudioThumbnailCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7253F21624BDA89F0094C385 /* AudioThumbnailCollectionCell.swift */; }; 7253F21924BDA89F0094C385 /* AudioThumbnailCollectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7253F21724BDA89F0094C385 /* AudioThumbnailCollectionCell.xib */; }; 7253F21B24BDAF890094C385 /* AudioPlayerViewController+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7253F21A24BDAF890094C385 /* AudioPlayerViewController+CollectionView.swift */; }; @@ -215,6 +218,11 @@ 46F87396204CC69500F1AF37 /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = ""; }; 499AAFCDBDAB4C05C7264992 /* Pods-AmahiAnywhere.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AmahiAnywhere.release.xcconfig"; path = "Pods/Target Support Files/Pods-AmahiAnywhere/Pods-AmahiAnywhere.release.xcconfig"; sourceTree = ""; }; 665E1C7EF1F0DEBF3A9809B0 /* Pods-AmahiAnywhere.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AmahiAnywhere.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AmahiAnywhere/Pods-AmahiAnywhere.debug.xcconfig"; sourceTree = ""; }; + 7229DB3724EA9A490081AEF9 /* HACModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HACModel.swift; sourceTree = ""; }; + 7229DB3924EAF4700081AEF9 /* NAULoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NAULoginController.swift; sourceTree = ""; }; + 7229DB4224EB303A0081AEF9 /* WifiGatewayIP.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WifiGatewayIP.m; sourceTree = ""; }; + 7229DB4624EB31910081AEF9 /* WifiGatewayIPHelper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = WifiGatewayIPHelper.c; sourceTree = ""; }; + 723E3D2124EBA26600FFFA9A /* WifiGatewayIP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WifiGatewayIP.h; sourceTree = ""; }; 7253F21624BDA89F0094C385 /* AudioThumbnailCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioThumbnailCollectionCell.swift; sourceTree = ""; }; 7253F21724BDA89F0094C385 /* AudioThumbnailCollectionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AudioThumbnailCollectionCell.xib; sourceTree = ""; }; 7253F21A24BDAF890094C385 /* AudioPlayerViewController+CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioPlayerViewController+CollectionView.swift"; sourceTree = ""; }; @@ -223,6 +231,7 @@ 7270E662248D14A6001BE439 /* AudioPlayerQueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerQueueViewController.swift; sourceTree = ""; }; 7270E664248D448F001BE439 /* AudioPlayerViewController + PlayerQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioPlayerViewController + PlayerQueue.swift"; sourceTree = ""; }; 727A95DF24D2DA350057C27C /* UIImageExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; + 7284755624F92C9A00DCB78B /* route.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = route.h; sourceTree = ""; }; 72BDA8B324A9ED6900B4469E /* QueueItemTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueItemTableViewCell.swift; sourceTree = ""; }; 72BDA8B424A9ED6900B4469E /* QueueItemTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = QueueItemTableViewCell.xib; sourceTree = ""; }; 72DAFE1B24B6276A00755E25 /* AudioPlayerDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerDataModel.swift; sourceTree = ""; }; @@ -390,6 +399,17 @@ path = Walkthrough; sourceTree = ""; }; + 723E3D2824EBA78500FFFA9A /* Gateway IP Utility */ = { + isa = PBXGroup; + children = ( + 7229DB4224EB303A0081AEF9 /* WifiGatewayIP.m */, + 723E3D2124EBA26600FFFA9A /* WifiGatewayIP.h */, + 7229DB4624EB31910081AEF9 /* WifiGatewayIPHelper.c */, + 7284755624F92C9A00DCB78B /* route.h */, + ); + path = "Gateway IP Utility"; + sourceTree = ""; + }; 7258718D2496BC6100AF0A61 /* Views */ = { isa = PBXGroup; children = ( @@ -442,6 +462,7 @@ 3B37EBAE22ED11650065CB77 /* Units.swift */, 9935DAB32301FA21004816E1 /* RecentFiles.swift */, 727A95DF24D2DA350057C27C /* UIImageExtension.swift */, + 723E3D2824EBA78500FFFA9A /* Gateway IP Utility */, ); path = Utils; sourceTree = ""; @@ -531,6 +552,7 @@ children = ( FB71BE99201CB2FC0005492C /* LoginViewController.swift */, C83C639C203992460089B9D8 /* LoginPresenter.swift */, + 7229DB3924EAF4700081AEF9 /* NAULoginController.swift */, ); path = Login; sourceTree = ""; @@ -562,6 +584,7 @@ 9935DAAE2301ED86004816E1 /* RecentFile+CoreDataClass.swift */, 3B2805E32312CA1C0022ED48 /* RecentFile+CoreDataProperties.swift */, 72DAFE1B24B6276A00755E25 /* AudioPlayerDataModel.swift */, + 7229DB3724EA9A490081AEF9 /* HACModel.swift */, ); path = Models; sourceTree = ""; @@ -893,6 +916,7 @@ 4605964B204F35E9004FA066 /* ServerRoute.swift in Sources */, 3B4DB99722A0431100AF287B /* ServerCollectionViewCell.swift in Sources */, 3B33325622BAA2AF00BC61EB /* FilesCollectionFooterView.swift in Sources */, + 7229DB3A24EAF4700081AEF9 /* NAULoginController.swift in Sources */, C8DEBFAB20BAE1D300B09AED /* ConnectionModeManager.swift in Sources */, C8ED025920B3E30300015846 /* URL.swift in Sources */, C8DA5B1A20D5DC2200F5A527 /* DownloadService.swift in Sources */, @@ -953,6 +977,7 @@ 3B2805E42312CA1C0022ED48 /* RecentFile+CoreDataProperties.swift in Sources */, 3B3F43DF22FECF7300BB42B0 /* DissmissAnimator.swift in Sources */, 725871932496C65300AF0A61 /* PlayerQueueContainerView.swift in Sources */, + 7229DB4324EB303A0081AEF9 /* WifiGatewayIP.m in Sources */, C83C637E2038D5150089B9D8 /* StringIdentifiers.swift in Sources */, 3B33325022BAA26600BC61EB /* FilesGridCollectionCell.swift in Sources */, 3BCAFBA322C537DE0044057E /* DownloadsGridCollectionCell.swift in Sources */, @@ -972,6 +997,7 @@ 46098D08204FFFBE00752EB6 /* ServerApi.swift in Sources */, 3B33325422BAA29700BC61EB /* FilesCollectionHeaderView.swift in Sources */, 3B3F43E122FECF9300BB42B0 /* Interactor.swift in Sources */, + 7229DB3824EA9A490081AEF9 /* HACModel.swift in Sources */, C8D86160209490230014D8AC /* WebViewController.swift in Sources */, 3BF1E81A22D0288700C531CD /* OfflineFileIndexes.swift in Sources */, 7253F21B24BDAF890094C385 /* AudioPlayerViewController+CollectionView.swift in Sources */, diff --git a/AmahiAnywhere/AmahiAnywhere/AmahiAnywhere-Bridging-Header.h b/AmahiAnywhere/AmahiAnywhere/AmahiAnywhere-Bridging-Header.h index 74bcac72c4f..8afb8de1c34 100644 --- a/AmahiAnywhere/AmahiAnywhere/AmahiAnywhere-Bridging-Header.h +++ b/AmahiAnywhere/AmahiAnywhere/AmahiAnywhere-Bridging-Header.h @@ -11,3 +11,4 @@ // #import "MobileVLCKit/MobileVLCKit.h" +#import "WifiGatewayIP.h" diff --git a/AmahiAnywhere/AmahiAnywhere/AppDelegate.swift b/AmahiAnywhere/AmahiAnywhere/AppDelegate.swift index a75dc747d48..3ae4e370812 100644 --- a/AmahiAnywhere/AmahiAnywhere/AppDelegate.swift +++ b/AmahiAnywhere/AmahiAnywhere/AppDelegate.swift @@ -57,6 +57,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } var orientationLock = UIInterfaceOrientationMask.all + let mainStoryboard: UIStoryboard = UIStoryboard(name: StoryBoardIdentifiers.main, bundle: nil) func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock @@ -92,9 +93,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { //LocalStorage.shared.delete(key: "walkthrough") self.window = UIWindow(frame: UIScreen.main.bounds) - let mainStoryboard: UIStoryboard = UIStoryboard(name: StoryBoardIdentifiers.main, bundle: nil) var initialViewController: UIViewController? = nil - + if LocalStorage.shared.contains(key: PersistenceIdentifiers.accessToken) { if useCastContainerViewController { @@ -111,16 +111,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.window?.rootViewController = initialViewController self.window?.makeKeyAndVisible() } - } else { - if LocalStorage.shared.contains(key: "walkthrough"){ - // User already completed the onboarding - initialViewController = mainStoryboard.instantiateInitialViewController() - }else{ - // User didn't complete the onboarding yet - initialViewController = mainStoryboard.instantiateViewController(withIdentifier: StoryBoardIdentifiers.walktrhoughViewController) + }else if let hac = LocalStorage.shared.getDictionary(for: PersistenceIdentifiers.hdaAuthCache) { + for ip in hac.keys{ + if let serverDetails = hac[ip]{ + let serverObject = HDAAuthCache(from: serverDetails) + if let authToken = serverObject.authToken{ + ServerApi.shared?.auth_token = authToken + let address = ApiEndPoints.getNauAddress(from: ip) + ServerApi.shared?.serverAddress = address + let rootVC = mainStoryboard.instantiateViewController(withIdentifier: "RootVC") as! RootContainerViewController + rootVC.isNAULogin = true + LocalStorage.shared.persist(true, for: PersistenceIdentifiers.isNAULogin) + self.window?.rootViewController = rootVC + self.window?.makeKeyAndVisible() + } + } } - self.window?.rootViewController = initialViewController - self.window?.makeKeyAndVisible() + if window?.rootViewController == nil{ + //none of the cached server had an auth_token fallback to login flow. + installLoginViewController() + } + } + + else { + installLoginViewController() } // Setting default layout view value @@ -153,6 +167,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } + func installLoginViewController(){ + var initialViewController : UIViewController? = nil + + if LocalStorage.shared.contains(key: "walkthrough"){ + // User already completed the onboarding + initialViewController = mainStoryboard.instantiateInitialViewController() + }else{ + // User didn't complete the onboarding yet + initialViewController = mainStoryboard.instantiateViewController(withIdentifier: StoryBoardIdentifiers.walktrhoughViewController) + } + self.window?.rootViewController = initialViewController + self.window?.makeKeyAndVisible() + } + func setupMiniController(){ self.window = UIWindow(frame: UIScreen.main.bounds) diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Local/LocalStorage.swift b/AmahiAnywhere/AmahiAnywhere/Data/Local/LocalStorage.swift index 3337ffadd6c..5941114468f 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Local/LocalStorage.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Local/LocalStorage.swift @@ -21,12 +21,29 @@ final class LocalStorage: NSObject { UserDefaults.standard.setValue(string, forKey: key); UserDefaults.standard.synchronize(); } + + public func persistDictionary(_ dictionary:[String:[String:String]],for key: String){ + UserDefaults.standard.set(dictionary, forKey: key) + } + + public func getDictionary(for key: String)->[String:[String:String]]?{ + return UserDefaults.standard.object(forKey: key) as? [String:[String:String]] + } + public func getString(key: String!) -> String? { UserDefaults.standard.synchronize() return UserDefaults.standard.value(forKey: key) as? String; } + public func getBool(_ key:String) -> Bool{ + return UserDefaults.standard.bool(forKey: key) + } + + public func persist(_ bool:Bool, for key:String){ + UserDefaults.standard.set(bool, forKey: key) + } + public func contains(key: String!) -> Bool{ return UserDefaults.standard.object(forKey: key) != nil } @@ -37,9 +54,20 @@ final class LocalStorage: NSObject { } public func logout(_ complete: () -> Void){ + var hac = getDictionary(for: PersistenceIdentifiers.hdaAuthCache) clearAll() persistString(string: "completed", key: "walkthrough") - complete(); + + //wiping auth_token for cached HDA + if hac != nil{ + for ip in hac!.keys{ + hac![ip]?[HACIdentifiers.auth_token] = "" + } + persistDictionary(hac!, for: PersistenceIdentifiers.hdaAuthCache) + } + + RecentsDatabaseHelper.shareInstance.clearAllRecents() + complete() } public func clearAll(){ diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Local/Models/HACModel.swift b/AmahiAnywhere/AmahiAnywhere/Data/Local/Models/HACModel.swift new file mode 100644 index 00000000000..e96c3b4c276 --- /dev/null +++ b/AmahiAnywhere/AmahiAnywhere/Data/Local/Models/HACModel.swift @@ -0,0 +1,46 @@ +// +// HACModel.swift +// AmahiAnywhere +// +// Created by Shresth Pratap Singh on 17/08/20. +// Copyright © 2020 Amahi. All rights reserved. +// + +import Foundation +import EVReflection + +struct HACIdentifiers{ + static let server_ip = "server_ip" + static let session_token = "session_token" + static let auth_token = "auth_token" + static let server_address = "server_address" +} + +struct HDAAuthCache{ + + var serverLocalIP:String? + var sessionToken:String? + var authToken:String? + var serverAddress:String? + + init(from dictionary:[String:String]) { + serverLocalIP = (dictionary[HACIdentifiers.server_ip] == "") ? nil : dictionary[HACIdentifiers.server_ip] + sessionToken = (dictionary[HACIdentifiers.session_token] == "") ? nil : dictionary[HACIdentifiers.session_token] + authToken = (dictionary[HACIdentifiers.auth_token] == "") ? nil : dictionary[HACIdentifiers.auth_token] + serverAddress = (dictionary[HACIdentifiers.server_address] == "") ? nil : dictionary[HACIdentifiers.server_address] + } + + init(ip:String?, sessionToken:String?, authToken:String?, serverAddress:String?) { + self.serverLocalIP = ip + self.sessionToken = sessionToken + self.authToken = authToken + self.serverAddress = serverAddress + } + + var toDictionary:[String:String]{ + return [HACIdentifiers.server_ip : serverLocalIP ?? "", + HACIdentifiers.session_token : sessionToken ?? "", + HACIdentifiers.auth_token : authToken ?? "", + HACIdentifiers.server_address : serverAddress ?? ""] + } +} diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Local/PersistenceIdentifiers.swift b/AmahiAnywhere/AmahiAnywhere/Data/Local/PersistenceIdentifiers.swift index 3d0c77b9fa3..28a99bc422f 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Local/PersistenceIdentifiers.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Local/PersistenceIdentifiers.swift @@ -14,4 +14,6 @@ struct PersistenceIdentifiers { static let accessToken = "access_token" static let prefConnection = "pref_connection" + static let hdaAuthCache = "hda_auth_cache" + static let isNAULogin = "nau_logged_in" } diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Local/RecentsDatabaseHelper.swift b/AmahiAnywhere/AmahiAnywhere/Data/Local/RecentsDatabaseHelper.swift index 8d91e0f8991..cb3e3a3c3dd 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Local/RecentsDatabaseHelper.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Local/RecentsDatabaseHelper.swift @@ -70,4 +70,15 @@ class RecentsDatabaseHelper { } } + func clearAllRecents(){ + let entityFetch = NSFetchRequest(entityName: "RecentFile") + let deleteRequest = NSBatchDeleteRequest(fetchRequest: entityFetch) + do{ + try context.execute(deleteRequest) + try context.save() + }catch(let error){ + AmahiLogger.log("Failed to clear Recents Files due to error : " + error.localizedDescription) + } + } + } diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/AmahiApi.swift b/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/AmahiApi.swift index 5b41462ee98..c723608d689 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/AmahiApi.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/AmahiApi.swift @@ -24,6 +24,10 @@ class AmahiApi { headers: headers, completion: completion) } + func login(pin:String,url:URL,compltion: @escaping (_ success:Bool,_ authToken:String?)->Void){ + Network.shared.login(pin: pin, url: url, completion: compltion) + } + func getServers(completion: @escaping (_ servers: [Server]?) -> Void ) { Network.shared.request(ApiEndPoints.fetchServers(), completion: completion) } diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/ServerApi.swift b/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/ServerApi.swift index 772eb05b5de..d1abc837aa6 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/ServerApi.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiCalls/ServerApi.swift @@ -11,11 +11,11 @@ import Alamofire import EVReflection class ServerApi { - public static var shared: ServerApi? + public static var shared: ServerApi? = ServerApi() - private var server: Server! + private var server: Server? private var serverRoute: ServerRoute? - private var serverAddress: String? + var serverAddress: String? public var auth_token: String? // if nil -> server is default welcome to amahi private init() {} @@ -44,9 +44,9 @@ class ServerApi { public func getServerHeaders() -> HTTPHeaders { if let authToken = auth_token{ - return [ "Session": server.session_token!, "Authorization": authToken] + return ["Session": (server?.session_token ?? ""), "Authorization": authToken] }else{ - return [ "Session": server.session_token! ] + return [ "Session": server?.session_token ?? "" ] } } @@ -102,13 +102,13 @@ class ServerApi { } func getShares(completion: @escaping (_ serverShares: [ServerShare]?) -> Void ) { - if serverRoute == nil{ - completion(nil) - return - } - - if serverAddress == nil{ - serverAddress = ConnectionModeManager.shared.currentConnectionBaseURL(serverRoute: serverRoute!) + if !LocalStorage.shared.getBool(PersistenceIdentifiers.isNAULogin){ + if serverRoute == nil{ + completion(nil) + } + if serverAddress == nil{ + serverAddress = ConnectionModeManager.shared.currentConnectionBaseURL(serverRoute: serverRoute!) + } } Network.shared.request(ApiEndPoints.getServerShares(serverAddress), headers: getServerHeaders(), completion: completion) @@ -181,7 +181,7 @@ class ServerApi { URLQueryItem(name: "s", value: file.parentShare!.name), URLQueryItem(name: "p", value: file.getPath()), URLQueryItem(name: "mtime", value: String(file.getLastModifiedEpoch())), - URLQueryItem(name: "session", value: server.session_token), + URLQueryItem(name: "session", value: (server?.session_token)), ] if let authToken = auth_token{ @@ -200,7 +200,7 @@ class ServerApi { URLQueryItem(name: "s", value: file.parentShare!.name), URLQueryItem(name: "p", value: file.getPath()), URLQueryItem(name: "mtime", value: String(file.getLastModifiedEpoch())), - URLQueryItem(name: "session", value: server.session_token) + URLQueryItem(name: "session", value: (server?.session_token ?? "")) ] if let authToken = auth_token{ diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiEndPoints.swift b/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiEndPoints.swift index 28113e59a11..25b9cb2d424 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiEndPoints.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Remote/ApiEndPoints.swift @@ -26,6 +26,14 @@ struct ApiEndPoints { return "\(serverUrl!)/shares" } + static func getNauAuthUrl(from ip:String)->URL?{ + return URL(string: "http://" + ip + ":4563/auth") + } + + static func getNauAddress(from ip:String) -> String{ + return "http://"+ip+":4563" + } + static func authenticateServerWithPin(_ serverUrl: String!) -> String! { return "\(serverUrl!)/auth" } diff --git a/AmahiAnywhere/AmahiAnywhere/Data/Remote/Model/ServerShare.swift b/AmahiAnywhere/AmahiAnywhere/Data/Remote/Model/ServerShare.swift index bf7560f372f..f2146310a1c 100644 --- a/AmahiAnywhere/AmahiAnywhere/Data/Remote/Model/ServerShare.swift +++ b/AmahiAnywhere/AmahiAnywhere/Data/Remote/Model/ServerShare.swift @@ -16,6 +16,7 @@ public class ServerShare: EVNetworkingObject { public var name: String? = nil public var tags: [String]? = nil public var mtime: Date? = nil + public var writable:Bool = false // Overriding setValue for ignores undefined keys override public func setValue(_ value: Any!, forUndefinedKey key: String) {} diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Cast/RootContainerViewController.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Cast/RootContainerViewController.swift index dae4d7839e2..29cdd26686a 100644 --- a/AmahiAnywhere/AmahiAnywhere/Presentation/Cast/RootContainerViewController.swift +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Cast/RootContainerViewController.swift @@ -23,7 +23,7 @@ class RootContainerViewController: UIViewController, GCKUIMiniMediaControlsViewC } } } - + var isNAULogin = false var overridenNavigationController: UINavigationController? override var navigationController: UINavigationController? { get { @@ -85,7 +85,16 @@ class RootContainerViewController: UIViewController, GCKUIMiniMediaControlsViewC override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { if segue.identifier == "NavigationVCEmbedSegue" { if let tabBarController = segue.destination as? UITabBarController{ - tabBarController.selectedIndex = 1 + if isNAULogin{ + let sharesVC = viewController(viewControllerClass: SharesViewController.self, from: StoryBoardIdentifiers.main) + sharesVC.isNAULogin = true + let navCon = UINavigationController(rootViewController: sharesVC) + tabBarController.viewControllers?[1] = navCon + navCon.tabBarItem = UITabBarItem(title: "HDA", image: UIImage(named: "tabBarHDA"), tag: 0) + tabBarController.selectedIndex = 1 + }else{ + tabBarController.selectedIndex = 1 + } } navigationController = (segue.destination as? UINavigationController) } diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesPresenter.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesPresenter.swift index 25d7bf63e2c..180c8abaca0 100644 --- a/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesPresenter.swift +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesPresenter.swift @@ -123,7 +123,7 @@ class FilesPresenter: BasePresenter { /* Auth-token for HDA authorisation in PIN */ let authToken = ServerApi.shared?.auth_token - let dict = ["day":day, "month":month!, "year":year!, "fileName":fileName, "fileURL":fileURL, "serverName":ServerApi.shared!.getServer()!.name!, "size":selectedFile.getFileSize(), "mimeType":mimeType, "mtimeDate":mtimeDate!, "authToken":authToken!, "path": path, "sizeNumber": selectedFile.size!] as [String : Any] + let dict = ["day":day, "month":month!, "year":year!, "fileName":fileName, "fileURL":fileURL, "serverName":(ServerApi.shared!.getServer()?.name! ?? ""), "size":selectedFile.getFileSize(), "mimeType":mimeType, "mtimeDate":mtimeDate!, "authToken":authToken!, "path": path, "sizeNumber": selectedFile.size!] as [String : Any] RecentsDatabaseHelper.shareInstance.save(object: dict) diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesViewController.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesViewController.swift index bc0362fc74f..ea3dd06761f 100644 --- a/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesViewController.swift +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Files/FilesViewController.swift @@ -96,7 +96,12 @@ class FilesViewController: BaseUIViewController, GCKRemoteMediaClientListener { super.viewDidLoad() setupNotifications() presenter = FilesPresenter(self) - setupFloaty() + if share.writable{ + floaty.isHidden = false + setupFloaty() + }else{ + floaty.isHidden = true + } setupLayoutView() setupRefreshControl() setupSearchBar() @@ -151,10 +156,27 @@ class FilesViewController: BaseUIViewController, GCKRemoteMediaClientListener { LocalStorage.shared.delete(key: serverName) } self.navigationController?.popToRootViewController(animated: true) + + if LocalStorage.shared.getBool(PersistenceIdentifiers.isNAULogin){ + self.signOutNAU() + } })) self.present(alertVC, animated: true, completion: nil) } + private func signOutNAU(){ + LocalStorage.shared.logout{} + let loginNavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() + if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let currentWindow = appDelegate.window{ + UIView.transition(with: currentWindow, duration: 0.3, options: .transitionFlipFromRight, animations: { + //removing strong references from all other VC to let ARC automatically delete them from memmory + currentWindow.rootViewController = loginNavigationController + currentWindow.makeKeyAndVisible() + }, completion: nil) + } + } + + func uploadImageTapped(){ let alertVC = UIAlertController(title: "Select your source", message: nil, preferredStyle: .actionSheet) @@ -377,10 +399,6 @@ class FilesViewController: BaseUIViewController, GCKRemoteMediaClientListener { self.removeOfflineFile(indexPath: indexPath) }! - let delete = self.creatAlertAction(StringLiterals.delete, style: .destructive) { (action) in - self.deleteFile(file) - }! - let stop = self.creatAlertAction(StringLiterals.stopDownload, style: .default) { (action) in if let offlineFile = OfflineFileIndexes.indexPathsForOfflineFiles[indexPath]{ DownloadService.shared.cancelDownload(offlineFile) @@ -397,8 +415,13 @@ class FilesViewController: BaseUIViewController, GCKRemoteMediaClientListener { } else if state == .downloading { actions.append(stop) } - - actions.append(delete) + if fileShare.writable{ + let delete = self.creatAlertAction(StringLiterals.delete, style: .destructive) { (action) in + self.deleteFile(file) + }! + + actions.append(delete) + } let cancel = self.creatAlertAction(StringLiterals.cancel, style: .cancel, clicked: nil)! actions.append(cancel) diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Login/LoginViewController.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Login/LoginViewController.swift index 519ea96e96d..73b62d88386 100644 --- a/AmahiAnywhere/AmahiAnywhere/Presentation/Login/LoginViewController.swift +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Login/LoginViewController.swift @@ -15,6 +15,8 @@ class LoginViewController: BaseUIViewController { @IBOutlet private weak var passwordInputField: SkyFloatingLabelTextField! @IBOutlet private weak var showHideButton: UIButton! + @IBOutlet weak var pinLoginButton: UIButton! + private var presenter: LoginPresenter! override func viewDidLoad() { @@ -72,6 +74,7 @@ class LoginViewController: BaseUIViewController { passwordInputField.isSecureTextEntry = true showHideButton.setImage(UIImage(named: "passHidden"), for: .normal) showHideButton.isHidden = true + navigationController?.setNavigationBarHidden(true, animated: false) } @@ -132,6 +135,12 @@ class LoginViewController: BaseUIViewController { } } + @IBAction func loginWithPIN(_ sender: UIButton) { + let nauVC = UIStoryboard(name: StoryBoardIdentifiers.main, bundle: nil).instantiateViewController(withIdentifier: StoryBoardIdentifiers.nauViewController) +// self.navigationController?.pushViewController(nauVC, animated: true) + self.present(nauVC, animated: true, completion: nil) + } + @IBAction func showHideTapped(_ sender: UIButton) { if passwordInputField.isSecureTextEntry{ showHideButton.setImage(UIImage(named: "passShown"), for: .normal) diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Login/NAULoginController.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Login/NAULoginController.swift new file mode 100644 index 00000000000..18076cc6374 --- /dev/null +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Login/NAULoginController.swift @@ -0,0 +1,310 @@ +// +// NAULoginController.swift +// AmahiAnywhere +// +// Created by Shresth Pratap Singh on 17/08/20. +// Copyright © 2020 Amahi. All rights reserved. +// + +import UIKit +import SkyFloatingLabelTextField +import Alamofire + +class NAULoginController: UIViewController, UITextFieldDelegate { + + private var availableIPAddress = Set() + private var isPingingIP:Bool = false{ + willSet{ + if !newValue{ + hideLoader() + if loginWaitingForIP{ + hideDelay() + loginUser() + } + } + } + } + private var loginWaitingForIP = false + private var userPin :String = "" + private let pinExpression = "[A-Za-z0-9]+" + private var userAuthenticated = false + + @IBOutlet weak var pinTextField: SkyFloatingLabelTextField! + @IBOutlet weak var loaderView: UIActivityIndicatorView! + @IBOutlet weak var submitButton: UIButton! + @IBOutlet weak var titleLabel: UILabel! + + @IBOutlet weak var delayLabel: UILabel! + + private let pingDispatchGroup = DispatchGroup() + private let cacheDispatchGroup = DispatchGroup() + private let loginDispatchGroup = DispatchGroup() + + override func viewDidLoad() { + super.viewDidLoad() + title = "PIN Login" + pinTextField.textAlignment = .center + pinTextField.delegate = self + + pingCachedIP() + probeServerIP() + + delayLabel.alpha = 0 + view.bringSubviewToFront(titleLabel) + } + + override func viewDidAppear(_ animated: Bool) { + let routerIP = WifiGatewayIP.getGatewayIP() + if routerIP == nil{ + showAlert(withTitle: "Could not locate wifi router!", message: "Please make sure wifi is connected.", actions: [UIAlertAction(title: "Ok", style: .default, handler: { (_) in + self.dismiss(animated: true, completion: nil) + })]) + } + NotificationCenter.default.addObserver(self, selector: #selector(unreachableHDA), name: .HDAUnreachable, object: nil) + } + + @objc func unreachableHDA(){ + let alertVC = UIAlertController(title: "Unable to reach HDA", message: "Please check if your HDA is connected and try again.", preferredStyle: .alert) + alertVC.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in + self.dismiss(animated: true, completion: nil) + })) + self.present(alertVC, animated: true, completion: nil) + } + + func probeServerIP(){ + if availableIPAddress.isEmpty{ + if let defaultGateway = WifiGatewayIP.getGatewayIP(){ + let gatewayBlocks = defaultGateway.components(separatedBy: ".") + let localSubnet = gatewayBlocks[0] + "." + gatewayBlocks[1] + "." + gatewayBlocks[2] + "." + let startingHost = (Int(gatewayBlocks[3]) ?? 1) + 1 + findAvailableIP(with: localSubnet, startingHost) + } + } + } + + private func pingCachedIP(){ + if let hac = LocalStorage.shared.getDictionary(for: PersistenceIdentifiers.hdaAuthCache){ + isPingingIP = true + for cachedIP in hac.keys { + cacheDispatchGroup.enter() + DispatchQueue.init(label: "cacheQueueFor_\(cachedIP)").async { + Network.shared.pingOnce(cachedIP,timeout: 1.2) { (success) in + if success{ + DispatchQueue.main.async { + AmahiLogger.log("Sucessfully pinged Cached IP :" + cachedIP + " for NAU") + self.availableIPAddress.insert(cachedIP) + } + } + self.cacheDispatchGroup.leave() + } + } + } + cacheDispatchGroup.notify(queue: .main) { [weak self] in + self?.isPingingIP = false + } + } + } + + @IBAction func cancelButtonTap(_ sender: UIButton) { + dismiss(animated: true, completion: nil) + } + + override func viewWillAppear(_ animated: Bool) { + self.navigationController?.setNavigationBarHidden(false, animated: false) + navigationController?.navigationBar.isTranslucent = false + navigationController?.navigationBar.barTintColor = UIColor(named:"tabBarBackground") + navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor(named:"textOpenColor")] + } + + override func viewWillDisappear(_ animated: Bool) { + self.navigationController?.setNavigationBarHidden(true, animated: false) + } + + @IBAction func submitPin(_ sender: UIButton) { + if let pin = pinTextField.text, !pin.isEmpty{ + if pinFormatIsValid(pin){ + userPin = pin + if !availableIPAddress.isEmpty{ + showLoader() + loginUser() + return + } + + if !isPingingIP{ + showAlert(withTitle: "Failed to locate HDA server!", message: nil, + actions: [UIAlertAction(title: "Try again?", style: .default, handler: { (_) in + self.probeServerIP() + self.showLoader() + }), + UIAlertAction(title: "continue with username", style: .default, handler: { (_) in + self.dismiss(animated: true, completion: nil) + })]) + }else{ + //wait for IP + showLoader() + DispatchQueue.main.asyncAfter(deadline: .now() + 5) {[weak self] in + self?.showDelay() + } + loginWaitingForIP = true + } + }else{ + pinTextField.errorColor = .red + pinTextField.errorMessage = "A 3-5 digit alpha-numeric pin is expected!" + } + }else{ + pinTextField.errorColor = .red + pinTextField.errorMessage = "Please enter a pin to continue!" + } + } + + private func loginUser(){ + loginWaitingForIP = false + + if availableIPAddress.isEmpty{ + showAlert(withTitle: "Failed to locate HDA server!", message: nil, + actions: [UIAlertAction(title: "Try again?", style: .default, handler: { (_) in + self.probeServerIP() + self.showLoader() + }), + UIAlertAction(title: "continue with username", style: .default, handler: { (_) in + self.navigationController?.popViewController(animated: true) + })]) + } + + for ip in availableIPAddress{ + if let url = ApiEndPoints.getNauAuthUrl(from: ip){ + loginDispatchGroup.enter() + AmahiApi.shared.login(pin: userPin, url: url) { (success, authToken) in + DispatchQueue.main.async { [weak self] in + self?.loginDispatchGroup.leave() + if success{ + self?.hideLoader() + ServerApi.shared?.auth_token = authToken + let address = ApiEndPoints.getNauAddress(from: ip) + ServerApi.shared?.serverAddress = address + + let authCache = HDAAuthCache(ip: ip, sessionToken: nil, authToken: authToken, serverAddress: address) + var storedCache = LocalStorage.shared.getDictionary(for: PersistenceIdentifiers.hdaAuthCache) + if storedCache != nil{ + storedCache![ip] = authCache.toDictionary + LocalStorage.shared.persistDictionary(storedCache!, for: PersistenceIdentifiers.hdaAuthCache) + }else{ + LocalStorage.shared.persistDictionary([ip:authCache.toDictionary], for: PersistenceIdentifiers.hdaAuthCache) + } + LocalStorage.shared.persist(true, for: PersistenceIdentifiers.isNAULogin) + self?.setupViewController() + self?.userAuthenticated = true + AmahiLogger.log("Successfully Logged in NAU on IP: " + ip) + }else{ + if let userIsAuthenticated = self?.userAuthenticated, !userIsAuthenticated{ + self?.userAuthenticated = false + } + AmahiLogger.log("NAU login failed for IP: " + ip) + } + } + } + } + } + + loginDispatchGroup.notify(queue: .main) { [weak self] in + if let userIsAuthenticated = self?.userAuthenticated, !userIsAuthenticated{ + self?.showAlert(withTitle: "Authentication failed!", message: "Please enter a valid PIN", actions: [UIAlertAction(title: "Ok", style: .default, handler: nil)]) + } + } + } + + private func setupViewController(){ + if let rootVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "RootVC") as? RootContainerViewController{ + + rootVC.isNAULogin = true + if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let currentWindow = appDelegate.window{ + UIView.transition(with: currentWindow, duration: 0.3, options: .transitionFlipFromRight, animations: { + currentWindow.rootViewController = rootVC + currentWindow.makeKeyAndVisible() + }, completion: nil) + } + } + } + + private func pinFormatIsValid(_ testString:String)->Bool{ + //evaluating pin regular expression + let pinTest = NSPredicate(format:"SELF MATCHES %@",pinExpression) + let expressionResult = pinTest.evaluate(with: testString) + + var isPinLengthValid = false + (testString.count >= 3 && testString.count <= 5) ? (isPinLengthValid = true) : (isPinLengthValid = false) + + return isPinLengthValid && expressionResult + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + (textField as! SkyFloatingLabelTextField).errorMessage = nil + return true + } + + func findAvailableIP(with networkAddress: String,_ host : Int){ + var hostDevice = host + while hostDevice <= 255{ + isPingingIP = true + pingDispatchGroup.enter() + + let ip = networkAddress + "\(hostDevice)" + + DispatchQueue.init(label: "queueFor\(hostDevice)").async { + Network.shared.pingOnce(ip,timeout: 1.2) { [weak self] (success) in + DispatchQueue.main.async { + if success{ + AmahiLogger.log("Sucessfully pinged IP : " + ip + " for NAU") + self?.availableIPAddress.insert(ip) + } + self?.pingDispatchGroup.leave() + } + } + } + hostDevice += 1 + } + + pingDispatchGroup.notify(queue: .main) { + self.isPingingIP = false + } + } + + private func showAlert(withTitle title:String?,message:String?,actions:[UIAlertAction]){ + hideLoader() + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + for action in actions{ + alertController.addAction(action) + } + present(alertController, animated: true) + } + + private func showLoader(){ + loaderView.startAnimating() + submitButton.isEnabled = false + pinTextField.isEnabled = false + submitButton.setTitle("", for: .normal) + } + + private func hideLoader(){ + loaderView.stopAnimating() + submitButton.isEnabled = true + pinTextField.isEnabled = true + submitButton.setTitle("SUBMIT", for: .normal) + } + + private func showDelay(){ + UIView.animate(withDuration: 1) {[weak self] in + self?.view.bringSubviewToFront(self!.delayLabel) + self?.titleLabel.alpha = 0 + self?.delayLabel.alpha = 1 + } + } + + private func hideDelay(){ + UIView.animate(withDuration: 1) {[weak self] in + self?.view.bringSubviewToFront(self!.titleLabel) + self?.titleLabel.alpha = 0 + self?.delayLabel.alpha = 1 + } + } +} diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Settings/SettingsViewController.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Settings/SettingsViewController.swift index 5f70d886b57..7a2a3f8b952 100644 --- a/AmahiAnywhere/AmahiAnywhere/Presentation/Settings/SettingsViewController.swift +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Settings/SettingsViewController.swift @@ -53,11 +53,11 @@ class SettingsViewController: BaseUITableViewController { internal func signOut() { self.dismiss(animated: false, completion: nil) LocalStorage.shared.logout{} - let loginVc = self.viewController(viewControllerClass: LoginViewController.self, from: StoryBoardIdentifiers.main) + let loginNavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let currentWindow = appDelegate.window{ UIView.transition(with: currentWindow, duration: 0.3, options: .transitionFlipFromRight, animations: { //removing strong references from all other VC to let ARC automatically delete them from memmory - currentWindow.rootViewController = loginVc + currentWindow.rootViewController = loginNavigationController currentWindow.makeKeyAndVisible() }, completion: nil) } diff --git a/AmahiAnywhere/AmahiAnywhere/Presentation/Shares/SharesViewController.swift b/AmahiAnywhere/AmahiAnywhere/Presentation/Shares/SharesViewController.swift index 97f20fd024f..656e03167d1 100644 --- a/AmahiAnywhere/AmahiAnywhere/Presentation/Shares/SharesViewController.swift +++ b/AmahiAnywhere/AmahiAnywhere/Presentation/Shares/SharesViewController.swift @@ -13,6 +13,7 @@ class SharesViewController: BaseUIViewController, UICollectionViewDelegate, UICo @IBOutlet fileprivate var sharesCollectionView: UICollectionView! @IBOutlet var serverNameLabel: UILabel! + var isNAULogin = false internal var server: Server? private var shares: [ServerShare] = [ServerShare]() private var presenter: SharesPresenter! @@ -35,7 +36,7 @@ class SharesViewController: BaseUIViewController, UICollectionViewDelegate, UICo override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(unreachableHDA), name: .HDAUnreachable, object: nil) - if server?.name != "Welcome to Amahi"{ + if server?.name != "Welcome to Amahi" && !isNAULogin{ navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Log out", style: .done, target: self, action: #selector(logOutTapped)) @@ -51,7 +52,6 @@ class SharesViewController: BaseUIViewController, UICollectionViewDelegate, UICo serverNameLabel.textColor = UIColor.white } - removePinVC() sharesCollectionView.delegate = self sharesCollectionView.dataSource = self sharesCollectionView.addSubview(refreshControl) @@ -60,7 +60,13 @@ class SharesViewController: BaseUIViewController, UICollectionViewDelegate, UICo serverNameLabel.text = ServerApi.shared!.getServer()?.name presenter = SharesPresenter(self) - presenter.loadServerRoute() + + if !isNAULogin{ + removePinVC() + presenter.loadServerRoute() + }else{ + presenter.getShares() + } NotificationCenter.default.addObserver(self, selector: #selector(expiredAuthTokenHDA), name: .HDATokenExpired, object: nil) } @@ -77,6 +83,9 @@ class SharesViewController: BaseUIViewController, UICollectionViewDelegate, UICo LocalStorage.shared.delete(key: serverName) } self.navigationController?.popToRootViewController(animated: true) + if self.isNAULogin{ + self.signOutNAU() + } })) self.present(alertVC, animated: true, completion: nil) } @@ -96,6 +105,18 @@ class SharesViewController: BaseUIViewController, UICollectionViewDelegate, UICo navigationController?.popViewController(animated: true) } + private func signOutNAU(){ + LocalStorage.shared.logout{} + let loginNavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() + if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let currentWindow = appDelegate.window{ + UIView.transition(with: currentWindow, duration: 0.3, options: .transitionFlipFromRight, animations: { + //removing strong references from all other VC to let ARC automatically delete them from memmory + currentWindow.rootViewController = loginNavigationController + currentWindow.makeKeyAndVisible() + }, completion: nil) + } + } + func removePinVC(){ var navigationVCs = self.navigationController!.viewControllers for (index, vc) in navigationVCs.enumerated(){ diff --git a/AmahiAnywhere/AmahiAnywhere/StoryBoards/Base.lproj/Main.storyboard b/AmahiAnywhere/AmahiAnywhere/StoryBoards/Base.lproj/Main.storyboard index fa9a410a737..6356cac6f0f 100644 --- a/AmahiAnywhere/AmahiAnywhere/StoryBoards/Base.lproj/Main.storyboard +++ b/AmahiAnywhere/AmahiAnywhere/StoryBoards/Base.lproj/Main.storyboard @@ -1,6 +1,6 @@ - - + + @@ -14,11 +14,11 @@ - + - + @@ -38,7 +38,7 @@ - + - + @@ -104,28 +104,44 @@ + + + + + + + + + + + + + + + + - + - + - - + + - + - - + + - + @@ -153,7 +169,7 @@ - + @@ -184,14 +200,14 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - + + + + + + - + - + - + - + @@ -293,7 +376,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIP.h b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIP.h new file mode 100644 index 00000000000..1290e76e8a7 --- /dev/null +++ b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIP.h @@ -0,0 +1,20 @@ +// +// WifiGatewayIP.h +// AmahiAnywhere +// +// Created by Shresth Pratap Singh on 18/08/20. +// Copyright © 2020 Amahi. All rights reserved. +// + +//#ifndef WifiGatewayIP_h +//#define WifiGatewayIP_h +// +// +//#endif /* WifiGatewayIP_h */ +#import + +@interface WifiGatewayIP : NSObject + + + (NSString *)getGatewayIP; + +@end diff --git a/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIP.m b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIP.m new file mode 100644 index 00000000000..da2c0bdafa4 --- /dev/null +++ b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIP.m @@ -0,0 +1,32 @@ +// +// WifiGatewayIP.m +// AmahiAnywhere +// +// Created by Shresth Pratap Singh on 18/08/20. +// Copyright © 2020 Amahi. All rights reserved. +// + +#import +#import "WifiGatewayIPHelper.c" +#import "WifiGatewayIP.h" +#import +#import +#include +#include + +@implementation WifiGatewayIP + ++ (NSString *)getGatewayIP { + NSString *ipString = nil; + struct in_addr gatewayaddr; + int r = getdefaultgateway(&(gatewayaddr.s_addr)); + if(r >= 0) { + ipString = [NSString stringWithFormat: @"%s",inet_ntoa(gatewayaddr)]; + } else { + NSLog(@"Could not locate gateway IP :- possibly Wifi is not connected"); + } + + return ipString; +} + +@end diff --git a/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIPHelper.c b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIPHelper.c new file mode 100644 index 00000000000..c5f16e56010 --- /dev/null +++ b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/WifiGatewayIPHelper.c @@ -0,0 +1,83 @@ +// +// WifiGatewayIP.c +// AmahiAnywhere +// +// Created by Shresth Pratap Singh on 18/08/20. +// Copyright © 2020 Amahi. All rights reserved. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +//Uncoment the following lines when building on simulator + +//#if TARGET_IPHONE_SIMULATOR +//#include +//#else +#include "route.h" +//#endif + +#define CTL_NET 4 + +#if defined(BSD) || defined(__APPLE__) + +#define ROUNDUP(a) \ +((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +int getdefaultgateway(in_addr_t * addr) +{ + int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, + NET_RT_FLAGS, RTF_GATEWAY}; + size_t l; + char * buf, * p; + struct rt_msghdr * rt; + struct sockaddr * sa; + struct sockaddr * sa_tab[RTAX_MAX]; + int i; + int r = -1; + if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) { + return -1; + } + if(l>0) { + buf = malloc(l); + if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) { + return -1; + } + for(p=buf; prtm_msglen) { + rt = (struct rt_msghdr *)p; + sa = (struct sockaddr *)(rt + 1); + for(i=0; irtm_addrs & (1 << i)) { + sa_tab[i] = sa; + sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); + } else { + sa_tab[i] = NULL; + } + } + + if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) + && sa_tab[RTAX_DST]->sa_family == AF_INET + && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { + + if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { + char ifName[128]; + if_indextoname(rt->rtm_index,ifName); + if(strcmp("en0",ifName)==0){ + *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; + r = 0; + } + } + } + } + free(buf); + } + return r; +} + +#endif diff --git a/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/route.h b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/route.h new file mode 100644 index 00000000000..e128131d2f4 --- /dev/null +++ b/AmahiAnywhere/AmahiAnywhere/Utils/Gateway IP Utility/route.h @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2000-2017 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)route.h 8.3 (Berkeley) 4/19/94 + * $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $ + */ + +#ifndef _NET_ROUTE_H_ +#define _NET_ROUTE_H_ +#include +#include +#include +#include + +/* + * These numbers are used by reliable protocols for determining + * retransmission behavior and are included in the routing structure. + */ +struct rt_metrics { + u_int32_t rmx_locks; /* Kernel leaves these values alone */ + u_int32_t rmx_mtu; /* MTU for this path */ + u_int32_t rmx_hopcount; /* max hops expected */ + int32_t rmx_expire; /* lifetime for route, e.g. redirect */ + u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ + u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ + u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ + u_int32_t rmx_rtt; /* estimated round trip time */ + u_int32_t rmx_rttvar; /* estimated rtt variance */ + u_int32_t rmx_pksent; /* packets sent using this route */ + u_int32_t rmx_state; /* route state */ + u_int32_t rmx_filler[3]; /* will be used for T/TCP later */ +}; + +/* + * rmx_rtt and rmx_rttvar are stored as microseconds; + */ +#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ + +#ifdef PRIVATE +struct route_old { + void *ro_rt; + uint32_t ro_flags; + struct sockaddr ro_dst; +}; +#endif /* PRIVATE */ + +#ifdef BSD_KERNEL_PRIVATE +#include +#include +#include +#include +#include + +/* + * Kernel resident routing tables. + * + * The routing tables are initialized when interface addresses + * are set by making entries for all directly connected interfaces. + */ + +/* forward declarations */ +struct ifnet_llreach_info; +struct rt_reach_info; + +/* + * IP route structure + * + * A route consists of a destination address and a reference + * to a routing entry. These are often held by protocols + * in their control blocks, e.g. inpcb. + */ +struct route { + /* + * N.B: struct route must begin with ro_{rt, lle, srcia, flags} + * because the code does some casts of a 'struct route_in6 *' + * to a 'struct route *'. + */ + struct rtentry *ro_rt; + struct llentry *ro_lle; + + struct ifaddr *ro_srcia; + uint32_t ro_flags; /* route flags (see below) */ + struct sockaddr ro_dst; +}; + +#define ROF_SRCIF_SELECTED 0x0001 /* source interface was selected */ +#if 0 +/* XXX These will be used in the changes coming in later */ +#define ROF_NORTREF 0x0002 /* doesn't hold reference on ro_rt */ +#define ROF_L2_ME 0x0004 /* dst L2 addr is our address */ +#define ROF_MAY_LOOP 0x0008 /* dst may require loop copy */ +#define ROF_HAS_HEADER 0x0010 /* mbuf already have its header prepended */ +#define ROF_REJECT 0x0020 /* Destination is reject */ +#define ROF_BLACKHOLE 0x0040 /* Destination is blackhole */ +#define ROF_HAS_GW 0x0080 /* Destination has GW */ +#endif +#define ROF_LLE_CACHE 0x0100 /* Cache link layer */ + +#define ROUTE_UNUSABLE(_ro) \ + ((_ro)->ro_rt == NULL || \ + ((_ro)->ro_rt->rt_flags & (RTF_UP|RTF_CONDEMNED)) != RTF_UP || \ + RT_GENID_OUTOFSYNC((_ro)->ro_rt)) + +#define _ROUTE_RELEASE_COMMON(_ro, _rnh_locked) do { \ + if ((_ro)->ro_rt != NULL) { \ + RT_LOCK_ASSERT_NOTHELD((_ro)->ro_rt); \ + if (_rnh_locked) \ + rtfree_locked((_ro)->ro_rt); \ + else \ + rtfree((_ro)->ro_rt); \ + (_ro)->ro_rt = NULL; \ + } \ + if ((_ro)->ro_srcia != NULL) { \ + IFA_REMREF((_ro)->ro_srcia); \ + (_ro)->ro_srcia = NULL; \ + (_ro)->ro_flags &= ~ROF_SRCIF_SELECTED; \ + } \ + if ((_ro)->ro_lle != NULL) { \ + LLE_REMREF((_ro)->ro_lle); \ + (_ro)->ro_lle = NULL; \ + (_ro)->ro_flags &= ~ROF_LLE_CACHE; \ + } \ +} while (0) + +#define ROUTE_RELEASE_LOCKED(_ro) _ROUTE_RELEASE_COMMON(_ro, TRUE) +#define ROUTE_RELEASE(_ro) _ROUTE_RELEASE_COMMON(_ro, FALSE) + +/* + * We distinguish between routes to hosts and routes to networks, + * preferring the former if available. For each route we infer + * the interface to use from the gateway address supplied when + * the route was entered. Routes that forward packets through + * gateways are marked so that the output routines know to address the + * gateway rather than the ultimate destination. + */ + +#define NRTT_HIST 10 +/* + * Kernel routing entry structure. + */ +struct rtentry { + struct radix_node rt_nodes[2]; /* tree glue, and other values */ +#define rt_key(r) (SA((r)->rt_nodes->rn_key)) +#define rt_mask(r) (SA((r)->rt_nodes->rn_mask)) + /* + * See bsd/net/route.c for synchronization notes. + */ + decl_lck_mtx_data(, rt_lock); /* lock for routing entry */ + uint32_t rt_refcnt; /* # held references */ + uint32_t rt_flags; /* up/down?, host/net */ + uint32_t rt_genid; /* route generation id */ + struct sockaddr *rt_gateway; /* value */ + struct ifnet *rt_ifp; /* the answer: interface to use */ + struct ifaddr *rt_ifa; /* the answer: interface addr to use */ + struct sockaddr *rt_genmask; /* for generation of cloned routes */ + void *rt_llinfo; /* pointer to link level info cache */ + void (*rt_llinfo_get_ri) /* llinfo get reachability info fn */ + (struct rtentry *, struct rt_reach_info *); + void (*rt_llinfo_get_iflri) /* ifnet llinfo get reach. info fn */ + (struct rtentry *, struct ifnet_llreach_info *); + void (*rt_llinfo_purge)(struct rtentry *); /* llinfo purge fn */ + void (*rt_llinfo_free)(void *); /* link level info free function */ + void (*rt_llinfo_refresh) (struct rtentry *); /* expedite llinfo refresh */ + struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ +#define rt_use rt_rmx.rmx_pksent + struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ + struct rtentry *rt_parent; /* cloning parent of this route */ + struct nstat_counts *rt_stats; /* route stats */ + void (*rt_if_ref_fn)(struct ifnet *, int); /* interface ref func */ + + uint32_t *rt_tree_genid; /* ptr to per-tree route_genid */ + uint64_t rt_expire; /* expiration time in uptime seconds */ + uint64_t base_calendartime; /* calendar time upon entry creation */ + uint64_t base_uptime; /* uptime upon entry creation */ + u_int32_t rtt_hist[NRTT_HIST]; /* RTT history sample by TCP connections */ + u_int32_t rtt_min; /* minimum RTT computed from history */ + u_int32_t rtt_expire_ts; /* RTT history expire timestamp */ + u_int8_t rtt_index; /* Index into RTT history */ + /* Event handler context for the rtentrt */ + struct eventhandler_lists_ctxt rt_evhdlr_ctxt; +}; + +enum { + ROUTE_STATUS_UPDATE = 1, + ROUTE_ENTRY_REFRESH, + ROUTE_ENTRY_DELETED, + ROUTE_LLENTRY_RESOLVED, + ROUTE_LLENTRY_UNREACH, + ROUTE_LLENTRY_CHANGED, + ROUTE_LLENTRY_STALE, + ROUTE_LLENTRY_TIMEDOUT, + ROUTE_LLENTRY_DELETED, + ROUTE_LLENTRY_EXPIRED, + ROUTE_LLENTRY_PROBED, + ROUTE_EVHDLR_DEREGISTER, +}; + +extern const char * route_event2str(int route_event); + +typedef void (*route_event_fn) (struct eventhandler_entry_arg, + struct sockaddr *, int, struct sockaddr *, int); +EVENTHANDLER_DECLARE(route_event, route_event_fn); + +/* + * Synchronize route entry's generation ID with the tree's. + */ +#define RT_GENID_SYNC(_rt) do { \ + if ((_rt)->rt_tree_genid != NULL) \ + (_rt)->rt_genid = *(_rt)->rt_tree_genid; \ +} while (0) + +/* + * Indicates whether or not the route entry's generation ID is stale. + */ +#define RT_GENID_OUTOFSYNC(_rt) \ + ((_rt)->rt_tree_genid != NULL && \ + *(_rt)->rt_tree_genid != (_rt)->rt_genid) + +#endif /* BSD_KERNEL_PRIVATE */ + +#define RTF_UP 0x1 /* route usable */ +#define RTF_GATEWAY 0x2 /* destination is a gateway */ +#define RTF_HOST 0x4 /* host entry (net otherwise) */ +#define RTF_REJECT 0x8 /* host or net unreachable */ +#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ +#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ +#define RTF_DONE 0x40 /* message confirmed */ +#define RTF_DELCLONE 0x80 /* delete cloned route */ +#define RTF_CLONING 0x100 /* generate new routes on use */ +#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ +#define RTF_LLINFO 0x400 /* DEPRECATED - exists ONLY for backward + compatibility */ +#define RTF_LLDATA 0x400 /* used by apps to add/del L2 entries */ +#define RTF_STATIC 0x800 /* manually added */ +#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ +#define RTF_NOIFREF 0x2000 /* not eligible for RTF_IFREF */ +#define RTF_PROTO2 0x4000 /* protocol specific routing flag */ +#define RTF_PROTO1 0x8000 /* protocol specific routing flag */ + +#define RTF_PRCLONING 0x10000 /* protocol requires cloning */ +#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +#define RTF_PROTO3 0x40000 /* protocol specific routing flag */ + /* 0x80000 unused */ +#define RTF_PINNED 0x100000 /* future use */ +#define RTF_LOCAL 0x200000 /* route represents a local address */ +#define RTF_BROADCAST 0x400000 /* route represents a bcast address */ +#define RTF_MULTICAST 0x800000 /* route represents a mcast address */ +#define RTF_IFSCOPE 0x1000000 /* has valid interface scope */ +#define RTF_CONDEMNED 0x2000000 /* defunct; no longer modifiable */ +#define RTF_IFREF 0x4000000 /* route holds a ref to interface */ +#define RTF_PROXY 0x8000000 /* proxying, no interface scope */ +#define RTF_ROUTER 0x10000000 /* host is a router */ +#define RTF_DEAD 0x20000000 /* Route entry is being freed */ + /* 0x40000000 and up unassigned */ + +#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ +#define RTF_BITS \ + "\020\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" \ + "\10DELCLONE\11CLONING\12XRESOLVE\13LLINFO\14STATIC\15BLACKHOLE" \ + "\16NOIFREF\17PROTO2\20PROTO1\21PRCLONING\22WASCLONED\23PROTO3" \ + "\25PINNED\26LOCAL\27BROADCAST\30MULTICAST\31IFSCOPE\32CONDEMNED" \ + "\33IFREF\34PROXY\35ROUTER" + +#define IS_DIRECT_HOSTROUTE(rt) \ + (((rt)->rt_flags & (RTF_HOST | RTF_GATEWAY)) == RTF_HOST) +/* + * Routing statistics. + */ +struct rtstat { + short rts_badredirect; /* bogus redirect calls */ + short rts_dynamic; /* routes created by redirects */ + short rts_newgateway; /* routes modified by redirects */ + short rts_unreach; /* lookups which failed */ + short rts_wildcard; /* lookups satisfied by a wildcard */ + short rts_badrtgwroute; /* route to gateway is not direct */ +}; + +/* + * Structures for routing messages. + */ +struct rt_msghdr { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + pid_t rtm_pid; /* identify sender */ + int rtm_seq; /* for sender to identify action */ + int rtm_errno; /* why failed */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + +struct rt_msghdr2 { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + int32_t rtm_refcnt; /* reference count */ + int rtm_parentflags; /* flags of the parent route */ + int rtm_reserved; /* reserved field set to 0 */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + +#ifdef PRIVATE +struct kev_netevent_apnfallbk_data { + pid_t epid; /* effective PID */ + uuid_t euuid; /* effective UUID */ +}; + +/* + * Route reachability info. + */ +struct rt_reach_info { + u_int32_t ri_refcnt; /* reference count */ + u_int32_t ri_probes; /* total # of probes */ + u_int64_t ri_snd_expire; /* tx expiration (calendar) time */ + u_int64_t ri_rcv_expire; /* rx expiration (calendar) time */ + int32_t ri_rssi; /* received signal strength */ + int32_t ri_lqm; /* link quality metric */ + int32_t ri_npm; /* node proximity metric */ +}; + +/* + * Extended routing message header (private). + */ +struct rt_msghdr_ext { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_int32_t rtm_index; /* index for associated ifp */ + u_int32_t rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + u_int32_t rtm_reserved; /* for future use */ + u_int32_t rtm_addrs; /* bitmask identifying sockaddrs in msg */ + pid_t rtm_pid; /* identify sender */ + int rtm_seq; /* for sender to identify action */ + int rtm_errno; /* why failed */ + u_int32_t rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ + struct rt_reach_info rtm_ri; /* route reachability info */ +}; +#endif /* PRIVATE */ + +#define RTM_VERSION 5 /* Up the ante and ignore older versions */ + +/* + * Message types. + */ +#define RTM_ADD 0x1 /* Add Route */ +#define RTM_DELETE 0x2 /* Delete Route */ +#define RTM_CHANGE 0x3 /* Change Metrics or flags */ +#define RTM_GET 0x4 /* Report Metrics */ +#define RTM_LOSING 0x5 /* RTM_LOSING is no longer generated by xnu + and is deprecated */ +#define RTM_REDIRECT 0x6 /* Told to use different route */ +#define RTM_MISS 0x7 /* Lookup failed on this address */ +#define RTM_LOCK 0x8 /* fix specified metrics */ +#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ +#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ +#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ +#define RTM_NEWADDR 0xc /* address being added to iface */ +#define RTM_DELADDR 0xd /* address being removed from iface */ +#define RTM_IFINFO 0xe /* iface going up/down etc. */ +#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ +#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */ +#ifdef PRIVATE +#define RTM_GET_SILENT 0x11 +#endif /* PRIVATE */ +#define RTM_IFINFO2 0x12 /* */ +#define RTM_NEWMADDR2 0x13 /* */ +#define RTM_GET2 0x14 /* */ +#ifdef PRIVATE +#define RTM_GET_EXT 0x15 +#endif /* PRIVATE */ + +/* + * Bitmask values for rtm_inits and rmx_locks. + */ +#define RTV_MTU 0x1 /* init or lock _mtu */ +#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ +#define RTV_EXPIRE 0x4 /* init or lock _expire */ +#define RTV_RPIPE 0x8 /* init or lock _recvpipe */ +#define RTV_SPIPE 0x10 /* init or lock _sendpipe */ +#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ +#define RTV_RTT 0x40 /* init or lock _rtt */ +#define RTV_RTTVAR 0x80 /* init or lock _rttvar */ +#ifdef PRIVATE +#define RTV_REFRESH_HOST 0x100 /* init host route to expedite refresh */ +#endif + +/* + * Bitmask values for rtm_addrs. + */ +#define RTA_DST 0x1 /* destination sockaddr present */ +#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ +#define RTA_NETMASK 0x4 /* netmask sockaddr present */ +#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ +#define RTA_IFP 0x10 /* interface name sockaddr present */ +#define RTA_IFA 0x20 /* interface addr sockaddr present */ +#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ +#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ + +/* + * Index offsets for sockaddr array for alternate internal encoding. + */ +#define RTAX_DST 0 /* destination sockaddr present */ +#define RTAX_GATEWAY 1 /* gateway sockaddr present */ +#define RTAX_NETMASK 2 /* netmask sockaddr present */ +#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ +#define RTAX_IFP 4 /* interface name sockaddr present */ +#define RTAX_IFA 5 /* interface addr sockaddr present */ +#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ +#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ +#define RTAX_MAX 8 /* size of array to allocate */ + +struct rt_addrinfo { + int rti_addrs; + struct sockaddr *rti_info[RTAX_MAX]; +}; + +#ifdef PRIVATE +/* + * For scoped routing; a zero interface scope value means nil/no scope. + */ +#define IFSCOPE_NONE 0 +#endif /* PRIVATE */ + +#ifdef BSD_KERNEL_PRIVATE +/* + * Generic call trace used by some subsystems (e.g. route, ifaddr) + */ +#define CTRACE_STACK_SIZE 8 /* depth of stack trace */ +#define CTRACE_HIST_SIZE 4 /* refcnt history size */ +typedef struct ctrace { + void *th; /* thread ptr */ + void *pc[CTRACE_STACK_SIZE]; /* PC stack trace */ +} ctrace_t; + +extern void ctrace_record(ctrace_t *); + +#define RT_LOCK_ASSERT_HELD(_rt) \ + LCK_MTX_ASSERT(&(_rt)->rt_lock, LCK_MTX_ASSERT_OWNED) + +#define RT_LOCK_ASSERT_NOTHELD(_rt) \ + LCK_MTX_ASSERT(&(_rt)->rt_lock, LCK_MTX_ASSERT_NOTOWNED) + +#define RT_LOCK(_rt) do { \ + rt_lock(_rt, FALSE); \ +} while (0) + +#define RT_LOCK_SPIN(_rt) do { \ + rt_lock(_rt, TRUE); \ +} while (0) + +#define RT_CONVERT_LOCK(_rt) do { \ + RT_LOCK_ASSERT_HELD(_rt); \ + lck_mtx_convert_spin(&(_rt)->rt_lock); \ +} while (0) + +#define RT_UNLOCK(_rt) do { \ + rt_unlock(_rt); \ +} while (0) + +#define RT_ADDREF_LOCKED(_rt) do { \ + rtref(_rt); \ +} while (0) + +/* + * Spin variant mutex is used here; caller is responsible for + * converting any previously-held similar lock to full mutex. + */ +#define RT_ADDREF(_rt) do { \ + RT_LOCK_SPIN(_rt); \ + RT_ADDREF_LOCKED(_rt); \ + RT_UNLOCK(_rt); \ +} while (0) + +#define RT_REMREF_LOCKED(_rt) do { \ + (void) rtunref(_rt); \ +} while (0) + +/* + * Spin variant mutex is used here; caller is responsible for + * converting any previously-held similar lock to full mutex. + */ +#define RT_REMREF(_rt) do { \ + RT_LOCK_SPIN(_rt); \ + RT_REMREF_LOCKED(_rt); \ + RT_UNLOCK(_rt); \ +} while (0) + +/* + * This macro calculates skew in wall clock, just in case the user changes the + * system time. This skew adjustment is required because we now keep the + * expiration times in uptime terms in the kernel, but the userland still + * expects expiration times in terms of calendar times. This is used when + * reporting rt_expire, ln_expire, etc. values to user space. + */ +#define NET_CALCULATE_CLOCKSKEW(cc, ic, cu, iu) \ + ((cc.tv_sec - ic) - (cu - iu)) + +extern unsigned int rt_verbose; +extern struct radix_node_head *rt_tables[AF_MAX+1]; +extern lck_mtx_t *rnh_lock; +extern uint32_t route_genid_inet; /* INET route generation count */ +#if INET6 +extern uint32_t route_genid_inet6; /* INET6 route generation count */ +#endif /* INET6 */ +extern int rttrash; +extern unsigned int rte_debug; + +struct ifmultiaddr; +struct proc; + +extern void route_init(void); +extern void routegenid_update(void); +extern void routegenid_inet_update(void); +extern void routegenid_inet6_update(void); +extern void rt_ifmsg(struct ifnet *); +extern void rt_missmsg(int, struct rt_addrinfo *, int, int); +extern void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *); +extern void rt_newmaddrmsg(int, struct ifmultiaddr *); +extern int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *); +extern void set_primary_ifscope(int, unsigned int); +extern unsigned int get_primary_ifscope(int); +extern boolean_t rt_primary_default(struct rtentry *, struct sockaddr *); +extern struct rtentry *rt_lookup(boolean_t, struct sockaddr *, + struct sockaddr *, struct radix_node_head *, unsigned int); +extern struct rtentry *rt_lookup_coarse(boolean_t, struct sockaddr *, + struct sockaddr *, struct radix_node_head *); +extern void rtalloc(struct route *); +extern void rtalloc_scoped(struct route *, unsigned int); +extern void rtalloc_ign(struct route *, uint32_t); +extern void rtalloc_scoped_ign(struct route *, uint32_t, unsigned int); +extern struct rtentry *rtalloc1(struct sockaddr *, int, uint32_t); +extern struct rtentry *rtalloc1_scoped(struct sockaddr *, int, uint32_t, + unsigned int); +extern struct rtentry *rtalloc1_scoped_locked(struct sockaddr *, int, + uint32_t, unsigned int); +extern void rtfree_locked(struct rtentry *); +extern void rtfree(struct rtentry *); +extern void rtref(struct rtentry *); +/* + * rtunref will decrement the refcount, rtfree will decrement and free if + * the refcount has reached zero and the route is not up. + * Unless you have good reason to do otherwise, use rtfree. + */ +extern int rtunref(struct rtentry *); +extern void rtsetifa(struct rtentry *, struct ifaddr *); +extern int rtinit(struct ifaddr *, int, int); +extern int rtinit_locked(struct ifaddr *, int, int); +extern int rtioctl(unsigned long, caddr_t, struct proc *); +extern void rtredirect(struct ifnet *, struct sockaddr *, struct sockaddr *, + struct sockaddr *, int, struct sockaddr *, struct rtentry **); +extern int rtrequest(int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, struct rtentry **); +extern int rtrequest_scoped(int, struct sockaddr *, struct sockaddr *, + struct sockaddr *, int, struct rtentry **, unsigned int); +extern int rtrequest_locked(int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, struct rtentry **); +extern int rtrequest_scoped_locked(int, struct sockaddr *, struct sockaddr *, + struct sockaddr *, int, struct rtentry **, unsigned int); +extern void sin_set_ifscope(struct sockaddr *, unsigned int); +extern unsigned int sin_get_ifscope(struct sockaddr *); +extern unsigned int sin6_get_ifscope(struct sockaddr *); +extern void rt_lock(struct rtentry *, boolean_t); +extern void rt_unlock(struct rtentry *); +extern struct sockaddr *rtm_scrub(int, int, struct sockaddr *, + struct sockaddr *, void *, uint32_t, kauth_cred_t *); +extern boolean_t rt_validate(struct rtentry *); +extern void rt_set_proxy(struct rtentry *, boolean_t); +extern void rt_set_gwroute(struct rtentry *, struct sockaddr *, + struct rtentry *); +extern void rt_revalidate_gwroute(struct rtentry *, struct rtentry *); +extern errno_t route_to_gwroute(const struct sockaddr *, struct rtentry *, + struct rtentry **); +extern void rt_setexpire(struct rtentry *, uint64_t); +extern void rt_str(struct rtentry *, char *, uint32_t, char *, uint32_t); +extern const char *rtm2str(int); +extern void route_copyin(struct route *, struct route *, size_t); +extern void route_copyout(struct route *, const struct route *, size_t); +extern boolean_t rt_ifa_is_dst(struct sockaddr *, struct ifaddr *); +extern struct sockaddr *sa_copy(struct sockaddr *, struct sockaddr_storage *, + unsigned int *); + +/* + * The following is used to enqueue work items for route events + * and also used to pass route event while walking the tree + */ +struct route_event { + struct rtentry *rt; + /* + * There's no reference taken on gwrt. + * We only use it to check whether we should + * point to rt_gateway or the embedded rt_addr + * structure. + */ + struct rtentry *gwrt; + union { + union sockaddr_in_4_6 _rtev_ipaddr; + struct sockaddr_dl _rtev_lladdr; + char _rtev_addr_bytes[DLIL_SDLMAXLEN]; + } rt_addr; + uint32_t route_event_code; + eventhandler_tag evtag; +}; + +#define rtev_ipaddr rt_addr._rtev_ipaddr +#define rtev_lladdr rt_addr._rtev_lladdr +#define rtev_addr_bytes rt_addr._rtev_addr_bytes + +extern void route_event_init(struct route_event *p_route_ev, struct rtentry *rt, + struct rtentry *gwrt, int route_ev_code); +extern int route_event_walktree(struct radix_node *rn, void *arg); +extern void route_event_enqueue_nwk_wq_entry(struct rtentry *, struct rtentry *, + uint32_t, eventhandler_tag, boolean_t); + +#endif /* BSD_KERNEL_PRIVATE */ +#endif /* _NET_ROUTE_H_ */ diff --git a/AmahiAnywhere/AmahiAnywhere/Utils/Network.swift b/AmahiAnywhere/AmahiAnywhere/Utils/Network.swift index 244c62d2675..14f92c92c63 100644 --- a/AmahiAnywhere/AmahiAnywhere/Utils/Network.swift +++ b/AmahiAnywhere/AmahiAnywhere/Utils/Network.swift @@ -215,4 +215,47 @@ public class Network { } return downloadRequest } + + public func pingOnce(_ ip:String,timeout:Double,completion: @escaping (_ success:Bool)->Void){ + let configuration = URLSessionConfiguration.default + configuration.timeoutIntervalForRequest = timeout + let hostUrl: String = "http://" + ip + + if let url = URL(string: hostUrl) { + var request = URLRequest(url: url) + request.httpMethod = "HEAD" + URLSession(configuration: configuration) + .dataTask(with: request) { (_, response, error) -> Void in + guard error == nil else { + completion(false) + return + } + guard (response as? HTTPURLResponse)? + .statusCode == 200 else { + completion(false) + return + } + completion(true) + } + .resume() + } + } + + public func login(pin:String,url:URL,completion: @escaping (_ success:Bool,_ authToken:String?)->Void){ + Alamofire.request(url, method: .post, parameters: ["pin":pin], encoding: JSONEncoding.default, headers: getDefaultHeaders()).responseJSON{ response in + + switch response.result{ + case .success(let json): + let dict = json as! NSDictionary + if let authToken = dict["auth_token"] as? String{ + completion(true,authToken) + }else{ + completion(false,nil) + } + case .failure(let error): + print(error.localizedDescription) + completion(false,nil) + } + } + } } diff --git a/AmahiAnywhere/AmahiAnywhere/Utils/StringIdentifiers.swift b/AmahiAnywhere/AmahiAnywhere/Utils/StringIdentifiers.swift index d32f85c2555..11847319214 100644 --- a/AmahiAnywhere/AmahiAnywhere/Utils/StringIdentifiers.swift +++ b/AmahiAnywhere/AmahiAnywhere/Utils/StringIdentifiers.swift @@ -24,6 +24,7 @@ struct StoryBoardIdentifiers { static let filesViewController = "FilesViewController" static let navigationBarController = "UINavigationBarController" static let recentsNavigationController = "RecentsNavigationBarController" + static let nauViewController = "NAULoginVC" } struct CellIdentifiers {