How can I logout in my SFSafariViewController - swift

I made app which login in SFSafariViewController. It works well when login. but after I logout if I try to login it again, I'm already logged in. This is because my automatic login information is stored in SFSafariViewController. I tried to delete cache and cookies but it doesn't work. :(
this is my login code.
func requestCode() {
let scope = "user"
let urlString = "https://github.com/login/oauth/authorize?client_id=\(clientId)&scope=\(scope)"
guard let url = URL(string: urlString) else {
return
}
URLCache.shared.removeAllCachedResponses()
if let cookies = HTTPCookieStorage.shared.cookies {
for cookie in cookies {
HTTPCookieStorage.shared.deleteCookie(cookie)
}
}
let safariViewController = SFSafariViewController(url: url)
safariViewController.delegate = self
safariViewController.modalPresentationStyle = .automatic
if let topViewController = UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).flatMap({ $0.windows }).first(where: { $0.isKeyWindow }) {
topViewController.rootViewController?.present(safariViewController, animated: true, completion: nil)
}
}

prefersEphemeralWebBrowserSession = true
it makes your browser to private mode!!!
so you don't need to logout.

Related

How to wait oauth callback for triggering handleRedirectURL in swift

I've those methods
func runOauth(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.oauth2!.afterAuthorizeOrFail = self.callBackOAuth
var url:URL?
do{
url = try appDelegate.oauth2!.authorizeURL(withRedirect:"kronos://oauth/callback", scope: "auth",params: ["tg":"addon/kronos/main","idx":"login.OAuth","formId":"iOS"])
do{
let authorizer = appDelegate.oauth2!.authorizer as! OAuth2Authorizer
safariVC = try authorizer.authorizeSafariEmbedded(from: self,at: url!)
}
/*catch error*/
}
}
func callBackOAuth(authParameters:OAuth2JSON!, error: OAuth2Error!){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if (error == nil && appDelegate.oauth2!.accessToken != nil){//OAuth succeed in
self.keychain!.set(appDelegate.oauth2!.accessToken!,forKey:"Token")
appDelegate.reloadView()
}else {/*handle errors*/}
}
and in AppDelegate
func application(_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
let site=components?.host
if site == "oauth"{//OAuth terminated
if components?.path == "/callback" {
let viewController = self.window?.rootViewController as! ViewController
self.oauth2!.handleRedirectURL(url)
viewController.hideSafariView()
}
}
return true
}
My issue is that as I trigger runOauth like that it happens that application is called before callBackOAuth so after oauth viewDidAppear is recalled but with keychain token not set, so here is a way to "wait" in application that token is not nil
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//initialize OAuth2 config parameters
appDelegate.oauth2 = OAuth2CodeGrant(settings: OAuthParams )
appDelegate.oauth2!.authConfig.authorizeContext = KronosWebsite?.window
appDelegate.oauth2!.useKeychain = false
appDelegate.oauth2!.authConfig.authorizeEmbeddedAutoDismiss = true
appDelegate.oauth2!.logger = OAuth2DebugLogger(.debug)
appDelegate.oauth2!.afterAuthorizeOrFail = self.callBackOAuth
let token=self.keychain!.get("Token")
if(token == nil){//no token found, we launch the OAuth
runOauth()
}
}
EDIT:
I've tried to use a DispatchGroup with no success:
groupOauth.enter() in runOauth
groupOauth.leave() in callBackOAuth
and in AppDelegate::application
viewController.groupOauth.notify(queue: DispatchQueue.main) {
self.oauth2!.handleRedirectURL(url)
viewController.hideSafariView()
}
I've a solution by deporting the call of the URL which logs the user (with the Oauth token stored in keychain) from viewDidAppear to viewDidLoad

App Delegate, after OAuth, can't close the WebView

I have this in my Appdelegate.swift
case .reddit:
if (url.host == "oauth-callback") {
AuthorizationManager.removeRedditToken()
print("Oauth Request..")
let urlc = URLComponents(url: url, resolvingAgainstBaseURL: false)
let bearerToken = urlc?.queryItems?.first(where: { $0.name == "code" })?.value
let tokenPromise = TokenManager.sharedInstance.fetchAccesTokenPromise(withBearerToken: bearerToken ?? "")
tokenPromise.done { (token) in
TokenManager.sharedInstance.accessToken = token.accessToken
TokenManager.sharedInstance.refrestToken = token.refreshToken
print("Access Token")
print(token.accessToken)
print("_______")
print(token.refreshToken)
AuthorizationManager.saveRedditToken(token: token.accessToken)
AuthorizationManager.saveRedditRefreshToken(token: token.refreshToken!)
}.catch { (error) in
print(error)
}
And I want to close the web view that opens during the open url function, but I can't figure out how to do it. The only way the Web View dismisses is by pressing "Done". It should close when I receive successfully the token. Dunno what can I do

Dynamic links only working in Simulator, and NOT on actual device

The dynamic links used to be working fine both on actual device, and also in the simulator. When I click on the link in the simulator (or pasting it in safari), I get redirected to the ".page.link" site where it says "open" - and clicking open opens the app perfectly. However, if I repeat the same steps on my actual device, I get redirected to the support url, and nothing happens (app doesn't open even though its installed on my phone).
This is my code in where I display a url
if let uid = Auth.auth().currentUser?.uid {
guard let link = URL(string: "https://www.testapp.com/uid=" + uid) else {
return
}
let dynamicLinksDomain = "testapp.page.link"
let linkBuilder = DynamicLinkComponents(link: link, domain: dynamicLinksDomain)
linkBuilder.iOSParameters = DynamicLinkIOSParameters(bundleID: "com.burgertralla.theGreat")
linkBuilder.shorten { (url, _, _) in
if let url = url {
self.shareTopLabel.text = url.absoluteString
}
}
}
And this is my AppDelegate:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
self.handleIncomingDynamicLink(dynamicLink: dynamicLink)
return true
}
return false
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
if let incomingUrl = userActivity.webpageURL {
let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingUrl, completion: { (dynamicLink, _) in
if let dynamicLink = dynamicLink, let _ = dynamicLink.url {
self.handleIncomingDynamicLink(dynamicLink: dynamicLink)
}
})
if linkHandled {
return linkHandled
}
}
return false
}
func handleIncomingDynamicLink(dynamicLink: DynamicLink) {
guard let pathComponents = dynamicLink.url?.pathComponents else {
return
}
for pathComponent in pathComponents {
if pathComponent.contains("uid=") {
let uid = pathComponent.drop(prefix: "uid=")
Database.database().reference(withPath: "profile/" + uid).observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists(), var data = snapshot.value as? [String: Any] {
data["uid"] = snapshot.key
let userProfileVC = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "UserProfileViewController") as! UserProfileViewController
if let tabBarVc = self.window?.rootViewController as? UITabBarController {
tabBarVc.selectedIndex = 1
if let discoveryVC = tabBarVc.viewControllers?[1] as? UINavigationController {
userProfileVC.selectedUser = data
discoveryVC.pushViewController(userProfileVC, animated: true)
}
}
}
}
}
}
}
Do anyone have any clue on whats going on here?
Thanks for the help guys :)
EDIT : It does work on my iPhone with Chrome, however not with Safari. I don't know why...

Set alamofire cookies permenantly

I am using Alamofire for my requests and I get cookies in some of them, everything works fine when I launch the app and use it but when I kill the app and reopen the cookies are not there anymore. I searched a lot and found this but none of the answers helped.
I try to save the cookies after each request and load them before sending request as below:
func saveCookies(response: DataResponse<Any>) {
let headerFields = response.response?.allHeaderFields as! [String: String]
let url = response.response?.url
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url!)
var cookieArray = [[HTTPCookiePropertyKey: Any]]()
for cookie in cookies {
cookieArray.append(cookie.properties!)
}
UserDefaults.standard.set(cookieArray, forKey: "savedCookies")
UserDefaults.standard.synchronize()
}
func loadCookies() {
guard let cookieArray = UserDefaults.standard.array(forKey: "savedCookies") as? [[HTTPCookiePropertyKey: Any]] else { return }
for cookieProperties in cookieArray {
if let cookie = HTTPCookie(properties: cookieProperties) {
HTTPCookieStorage.shared.setCookie(cookie)
}
}
}
But still when I kill the app, I can't get the data.
Try to save your cookies in UserDefaults like this:
var authToken: String {
get {
return defaults.value(forKey: TOKEN_KEY) as! String
}
set {
defaults.set(newValue, forKey: TOKEN_KEY)
}
}

Load page into webview swift 2 from java class

I am developing an App for the iPhone using Xwebview which enables me to download a page then interact with the javascript on the downloaded page.
All works, but if the internet connection drops, a default local page is loaded, informing the user there is no internet connection. The page displays a retry button that, when pressed checks, the internet connection: if the connection is made the app tries to connect again to the external page and load the page into the webview.
I cannot get this to work: the code downloads the page (I can see this in my session data) but I can't get that page to load back into the webview.
override func viewDidLoad() {
super.viewDidLoad()
login()
}
func login()
{
// *********** Get stored hashkey **************
let hashcode = getHashcode()
// ********** Check network connection *********
let netConnection = Connection.isConnectedToNetwork()
print("net connection: ", netConnection)
if netConnection == true
{
if hashcode != "00000"
{
print("local key found", hashcode)
// We dont have local key
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
//webview.loadRequest(NSURLRequest(URL: NSURL(string: "about:blank")!))
view.addSubview(webview)
webview.loadPlugin(jsapi(), namespace: "jsapi")
let url:NSURL = NSURL(string: serverLocation + onlineLoginApi)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let paramString = "/?username=username&password=password"
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.downloadTaskWithRequest(request) {
(
let location, let response, let error) in
guard let _:NSURL = location, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let urlContents = try! NSString(contentsOfURL: location!, encoding: NSUTF8StringEncoding)
guard let _:NSString = urlContents else {
print("error")
return
}
print(urlContents)
}
task.resume()
// you must tell webview to load response
webview.loadRequest(request)
}
else{
print("local key found", hashcode)
// ********* Found local key go to site pass key over ************
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
view.addSubview(webview)
webview.loadPlugin(jsapi(), namespace: "jsapi")
let req = NSMutableURLRequest(URL: NSURL(string:serverLocation + onlineLoginApi + "?hashcode=\(hashcode)")!)
req.HTTPMethod = "POST"
req.HTTPBody = "/?hashcode=\(hashcode)".dataUsingEncoding(NSUTF8StringEncoding)
NSURLSession.sharedSession().dataTaskWithRequest(req)
{ data, response, error in
if error != nil
{
//Your HTTP request failed.
print(error!.localizedDescription)
} else {
//Your HTTP request succeeded
print(String(data: data!, encoding: NSUTF8StringEncoding))
}
}.resume()
webview.loadRequest(req)
}
}
else{
// No connection to internet
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
view.addSubview(webview)
webview.loadPlugin(jsapi(), namespace: "jsapi")
let root = NSBundle.mainBundle().resourceURL!
let url = root.URLByAppendingPathComponent("/www/error-no-connection.html")
webview.loadFileURL(url, allowingReadAccessToURL: root)
print("No internet connection")
}
}
class jsapi: NSObject {
// Reconnect button on interface
func retryConnection()
{
print("Reconnect clicked")
dispatch_async(dispatch_get_main_queue())
{
let netConnections = Connection.isConnectedToNetwork()
if netConnections == true {
let netalert = UIAlertView(title: "Internet on line", message: nil, delegate: nil, cancelButtonTitle: "OK")
netalert.show()
let url = self.serverLocation + self.onlineLoginApi
let hashcode = ViewController().getHashcode()
if(hashcode != "00000") {
let url = url + "?hashcode=\(hashcode)"
print("url: ", url)
}
ViewController().loadPagelive(url)
}
else{
let netalert = UIAlertView(title: "Internet off line", message: nil, delegate: nil, cancelButtonTitle: "OK")
netalert.show()
}
}
print("retryConnect end")
}
}
You try to perform the loadPagelive(url) on a new instance of your ViewController, not on the current one shown on the screen, that's why you don't see any update.
You should create a delegate or a completion block in order to execute code on you ViewController instance loaded on the screen: every time you do ViewController(), a new object is created.
You can try using the delegate pattern, which is simple to achieve. I will try to focus on the important part and create something that can be used with your existing code:
class ViewController: UIViewController {
let jsapi = jsapi() // You can use only 1 instance
override func viewDidLoad() {
super.viewDidLoad()
// Set your ViewController as a delegate, so the jsapi can update it
jsapi.viewController = self
login()
}
func loadPagelive(_ url: URL) {
// Load page, probably you already have it
}
}
class jsapi: NSObject {
weak var viewController: ViewController?
func retryConnection() {
// We check if the delegate is set, otherwise it won't work
guard viewController = viewController else {
print("Error: delegate not available")
}
[... your code ...]
// We call the original (and hopefully unique) instance of ViewController
viewController.loadPagelive(url)
}
}