Skip to content
Open
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
22 changes: 19 additions & 3 deletions WordPress/Classes/Utility/Networking/RequestAuthenticator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
/// - completion: this will be called with either the request for
/// authentication, or a request for the original URL.
///
@objc func request(url: URL, cookieJar: CookieJar, completion: @escaping (URLRequest) -> Void) {
func request(url: URL, cookieJar: CookieJar, completion: @escaping (URLRequest) -> Void) {
switch self.credentials {
case .dotCom(let username, let authToken, let authenticationType):
requestForWPCom(
Expand Down Expand Up @@ -312,15 +312,31 @@
}

private extension RequestAuthenticator {
static let wordPressComLoginUrl = URL(string: "https://wordpress.com/wp-login.php")!
static let wordPressComLoginUrls: Set<URL> = [
URL(string: "https://wordpress.com/wp-login.php")!,

Check warning on line 316 in WordPress/Classes/Utility/Networking/RequestAuthenticator.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor your code to get this URI from a customizable parameter.

See more on https://sonarcloud.io/project/issues?id=wordpress-mobile_WordPress-iOS&issues=AZrjSr_gTNjg9jrC77p0&open=AZrjSr_gTNjg9jrC77p0&pullRequest=25045
URL(string: "https://wordpress.com/log-in")!

Check warning on line 317 in WordPress/Classes/Utility/Networking/RequestAuthenticator.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor your code to get this URI from a customizable parameter.

See more on https://sonarcloud.io/project/issues?id=wordpress-mobile_WordPress-iOS&issues=AZrjSr_gTNjg9jrC77p1&open=AZrjSr_gTNjg9jrC77p1&pullRequest=25045
]
}

extension RequestAuthenticator {
func isLogin(url: URL) -> Bool {
// For some reason, the in-app browser may open Safari when tapping certain links.
// The "login URLs" are displayed within the in-app browser, which includes atomic site login (wp-login.php)
// and WordPress.com sign-in web pages.

var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.queryItems = nil
guard let normalized = components?.url else { return false }

if RequestAuthenticator.wordPressComLoginUrls.contains(normalized) {
return true
}

if case let .dotCom(_, _, .atomic(loginURL)) = credentials, normalized.absoluteString == loginURL {
return true
}

return components?.url == RequestAuthenticator.wordPressComLoginUrl
return false
}
}

Expand Down
60 changes: 13 additions & 47 deletions WordPress/Classes/Utility/WebViewController/CookieJar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import WebKit
/// Provides a common interface to look for a logged-in WordPress cookie in different
/// cookie storage systems.
///
@objc protocol CookieJar {
protocol CookieJar: AnyObject {
func getCookies(url: URL, completion: @escaping ([HTTPCookie]) -> Void)
func getCookies(completion: @escaping ([HTTPCookie]) -> Void)
func hasWordPressSelfHostedAuthCookie(for url: URL, username: String, completion: @escaping (Bool) -> Void)
Expand All @@ -14,28 +14,18 @@ import WebKit
func setCookies(_ cookies: [HTTPCookie], completion: @escaping () -> Void)
}

// As long as CookieJar is @objc, we can't have shared methods in protocol
// extensions, as it needs to be accessible to Obj-C.
// Whenever we migrate enough code so this doesn't need to be called from Swift,
// a regular CookieJar protocol with shared implementation on an extension would suffice.
//
// Also, although you're not supposed to use this outside this file, it can't be private
// since we're subclassing HTTPCookieStorage (which conforms to this) in MockCookieJar in
// the test target, and the swift compiler will crash when doing that ¯\_(ツ)_/¯
//
// https://bugs.swift.org/browse/SR-2370
//
protocol CookieJarSharedImplementation: CookieJar {
}

extension CookieJarSharedImplementation {
func _hasWordPressComAuthCookie(username: String, atomicSite: Bool, completion: @escaping (Bool) -> Void) {
extension CookieJar {
func hasWordPressComAuthCookie(username: String, atomicSite: Bool, completion: @escaping (Bool) -> Void) {
let url = URL(string: "https://wordpress.com/")!

return _hasWordPressAuthCookie(for: url, username: username, atomicSite: atomicSite, completion: completion)
return hasWordPressAuthCookie(for: url, username: username, atomicSite: atomicSite, completion: completion)
}

func _hasWordPressAuthCookie(for url: URL, username: String, atomicSite: Bool, completion: @escaping (Bool) -> Void) {
func hasWordPressSelfHostedAuthCookie(for url: URL, username: String, completion: @escaping (Bool) -> Void) {
hasWordPressAuthCookie(for: url, username: username, atomicSite: false, completion: completion)
}

private func hasWordPressAuthCookie(for url: URL, username: String, atomicSite: Bool, completion: @escaping (Bool) -> Void) {
getCookies(url: url) { (cookies) in
let cookie = cookies
.contains(where: { cookie in
Expand All @@ -46,14 +36,14 @@ extension CookieJarSharedImplementation {
}
}

func _removeWordPressComCookies(completion: @escaping () -> Void) {
func removeWordPressComCookies(completion: @escaping () -> Void) {
getCookies { [unowned self] (cookies) in
self.removeCookies(cookies.filter({ $0.domain.hasSuffix(".wordpress.com") }), completion: completion)
}
}
}

extension HTTPCookieStorage: CookieJarSharedImplementation {
extension HTTPCookieStorage: CookieJar {
func getCookies(url: URL, completion: @escaping ([HTTPCookie]) -> Void) {
completion(cookies(for: url) ?? [])
}
Expand All @@ -62,23 +52,11 @@ extension HTTPCookieStorage: CookieJarSharedImplementation {
completion(cookies ?? [])
}

func hasWordPressComAuthCookie(username: String, atomicSite: Bool, completion: @escaping (Bool) -> Void) {
_hasWordPressComAuthCookie(username: username, atomicSite: atomicSite, completion: completion)
}

func hasWordPressSelfHostedAuthCookie(for url: URL, username: String, completion: @escaping (Bool) -> Void) {
_hasWordPressAuthCookie(for: url, username: username, atomicSite: false, completion: completion)
}

func removeCookies(_ cookies: [HTTPCookie], completion: @escaping () -> Void) {
cookies.forEach(deleteCookie(_:))
completion()
}

func removeWordPressComCookies(completion: @escaping () -> Void) {
_removeWordPressComCookies(completion: completion)
}

func setCookies(_ cookies: [HTTPCookie], completion: @escaping () -> Void) {
for cookie in cookies {
setCookie(cookie)
Expand All @@ -88,7 +66,7 @@ extension HTTPCookieStorage: CookieJarSharedImplementation {
}
}

extension WKHTTPCookieStore: CookieJarSharedImplementation {
extension WKHTTPCookieStore: CookieJar {
func getCookies(url: URL, completion: @escaping ([HTTPCookie]) -> Void) {

// This fixes an issue with `getAllCookies` not calling its completion block (related: https://stackoverflow.com/q/55565188)
Expand Down Expand Up @@ -127,14 +105,6 @@ extension WKHTTPCookieStore: CookieJarSharedImplementation {
getAllCookies(completion)
}

func hasWordPressComAuthCookie(username: String, atomicSite: Bool, completion: @escaping (Bool) -> Void) {
_hasWordPressComAuthCookie(username: username, atomicSite: atomicSite, completion: completion)
}

func hasWordPressSelfHostedAuthCookie(for url: URL, username: String, completion: @escaping (Bool) -> Void) {
_hasWordPressAuthCookie(for: url, username: username, atomicSite: false, completion: completion)
}

func removeCookies(_ cookies: [HTTPCookie], completion: @escaping () -> Void) {
let group = DispatchGroup()
cookies
Expand All @@ -151,10 +121,6 @@ extension WKHTTPCookieStore: CookieJarSharedImplementation {
completion()
}

func removeWordPressComCookies(completion: @escaping () -> Void) {
_removeWordPressComCookies(completion: completion)
}

func setCookies(_ cookies: [HTTPCookie], completion: @escaping () -> Void) {
guard let cookie = cookies.last else {
return completion()
Expand All @@ -170,7 +136,7 @@ extension WKHTTPCookieStore: CookieJarSharedImplementation {

#if DEBUG
func __removeAllWordPressComCookies() {
var jars = [CookieJarSharedImplementation]()
var jars = [CookieJar]()
jars.append(HTTPCookieStorage.shared)
jars.append(WKWebsiteDataStore.default().httpCookieStore)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ struct DebugMenuView: View {
@StateObject private var viewModel = DebugMenuViewModel()
@State private var isShowingWebViewURLDialog = false
@State private var webViewURL = ""
@State private var isAuthenticatedMode = true

fileprivate var navigation: NavigationContext

Expand All @@ -35,7 +36,11 @@ struct DebugMenuView: View {
Button(SharedStrings.Button.cancel, role: .cancel) {
}
Button(SharedStrings.Button.view) {
presentAuthenticatedWebView()
if isAuthenticatedMode {
presentAuthenticatedWebView()
} else {
presentUnauthenticatedWebView()
}
}
}
}
Expand Down Expand Up @@ -86,6 +91,12 @@ struct DebugMenuView: View {
@ViewBuilder private var webView: some View {
Button(Strings.webViewRow) {
webViewURL = Blog.lastUsed(in: ContextManager.shared.mainContext)?.url ?? ""
isAuthenticatedMode = true
isShowingWebViewURLDialog = true
}
Button(Strings.unauthenticatedWebViewRow) {
webViewURL = ""
isAuthenticatedMode = false
isShowingWebViewURLDialog = true
}
}
Expand Down Expand Up @@ -136,6 +147,16 @@ struct DebugMenuView: View {
navigation.push(webViewController)
}

private func presentUnauthenticatedWebView() {
guard let url = URL(string: webViewURL) else {
preconditionFailure("Invalid URL")
return
}

let webViewController = WebViewControllerFactory.controller(url: url, source: "debug_menu")
navigation.push(webViewController)
}

private var readerSettings: some View {
let viewController = SettingsTextViewController(text: ReaderCSS().customAddress, placeholder: Strings.readerURLPlaceholder, hint: Strings.readerURLHint)
viewController.title = Strings.readerCssTitle
Expand Down Expand Up @@ -257,6 +278,7 @@ private enum Strings {
static let weeklyRoundup = NSLocalizedString("debugMenu.weeklyRoundup", value: "Weekly Roundup", comment: "Weekly Roundup debug menu item")
static let booleanUserDefaults = NSLocalizedString("debugMenu.booleanUserDefaults", value: "Boolean User Defaults", comment: "Boolean User Defaults debug menu item")
static let webViewRow = NSLocalizedString("debugMenu.webView.row", value: "Browse as loggedin account", comment: "Debug menu item to present an authenticated web view for the currently displayed site")
static let unauthenticatedWebViewRow = NSLocalizedString("debugMenu.webView.unauthenticatedRow", value: "Open a web browser", comment: "Debug menu item to present an unauthenticated web view")
static let webViewDialogTitle = NSLocalizedString("debugMenu.webView.dialogTitle", value: "Enter URL", comment: "Title for web view URL input dialog")

static let showAllTips = NSLocalizedString("debugMenu.showAllTips", value: "Show All Tips", comment: "Debug Menu action for TipKit")
Expand Down