From 817f5d1732c0267800226302136a87753410956a Mon Sep 17 00:00:00 2001 From: rishabhpoddar Date: Tue, 7 May 2024 13:26:10 +0530 Subject: [PATCH] makes code and version changes --- CHANGELOG.md | 8 +++ SuperTokensIOS.podspec | 2 +- SuperTokensIOS/Classes/Utils.swift | 83 ++++++++++++-------------- SuperTokensIOS/Classes/Version.swift | 2 +- testHelpers/testapp/Tests/config.swift | 50 ++++++++++++---- 5 files changed, 89 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f9b83..b760a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.3.0] - 2024-05-07 + +### Breaking change + +The `shouldDoInterceptionBasedOnUrl` function now returns true: +- If `sessionTokenBackendDomain` is a valid subdomain of the URL's domain. This aligns with the behavior of browsers when sending cookies to subdomains. +- Even if the ports of the URL you are querying are different compared to the `apiDomain`'s port ot the `sessionTokenBackendDomain` port (as long as the hostname is the same, or a subdomain of the `sessionTokenBackendDomain`): https://github.com/supertokens/supertokens-website/issues/217 + ## [0.2.7] - 2024-03-14 - New FDI version support: 1.19 diff --git a/SuperTokensIOS.podspec b/SuperTokensIOS.podspec index 2feb527..6155ae8 100644 --- a/SuperTokensIOS.podspec +++ b/SuperTokensIOS.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'SuperTokensIOS' - s.version = "0.2.7" + s.version = "0.3.0" s.summary = 'SuperTokens SDK for using login and session management functionality in iOS apps' # This description is used to generate tags and improve search results. diff --git a/SuperTokensIOS/Classes/Utils.swift b/SuperTokensIOS/Classes/Utils.swift index db0454a..9f5c50c 100644 --- a/SuperTokensIOS/Classes/Utils.swift +++ b/SuperTokensIOS/Classes/Utils.swift @@ -63,44 +63,38 @@ class NormalisedInputType { } internal static func sessionScopeHelper(sessionScope: String) throws -> String { - var trimmedSessionScope = sessionScope.trim() - + var trimmedSessionScope = sessionScope.trim().lowercased() + if trimmedSessionScope.starts(with: ".") { trimmedSessionScope = trimmedSessionScope.substring(fromIndex: 1) } - + if !trimmedSessionScope.starts(with: "http://") && !trimmedSessionScope.starts(with: "https://") { trimmedSessionScope = "http://" + trimmedSessionScope } - + do { guard let url: URL = URL(string: trimmedSessionScope), let host: String = url.host else { throw SDKFailableError.failableError } - - trimmedSessionScope = host - - if trimmedSessionScope.starts(with: ".") { - trimmedSessionScope = trimmedSessionScope.substring(fromIndex: 1) - } - - return trimmedSessionScope + + return host } catch { throw SuperTokensError.initError(message: "Please provide a valid sessionScope") } } - + internal static func normaliseSessionScopeOrThrowError(sessionScope: String) throws -> String { let noDotNormalised = try sessionScopeHelper(sessionScope: sessionScope) - + if noDotNormalised == "localhost" || Utils.isIpAddress(input: noDotNormalised) { return noDotNormalised } - + if sessionScope.starts(with: ".") { return "." + noDotNormalised } - + return noDotNormalised } @@ -156,42 +150,43 @@ class NormalisedInputType { internal class Utils { internal static func shouldDoInterception(toCheckURL: String, apiDomain: String, cookieDomain: String?) throws -> Bool { - let _toCheckURL: String = try NormalisedURLDomain.normaliseUrlDomainOrThrowError(input: toCheckURL) - var _apiDomain: String = apiDomain - - guard let urlObj: URL = URL(string: _toCheckURL), let hostname: String = urlObj.host else { + let normalizedToCheckURL = try NormalisedURLDomain.normaliseUrlDomainOrThrowError(input: toCheckURL) + guard let urlObj = URL(string: normalizedToCheckURL), let hostname = urlObj.host else { throw SDKFailableError.failableError } - + var domain = hostname - - if cookieDomain == nil { - domain = urlObj.port == nil ? domain : domain + ":" + "\(urlObj.port!)" - _apiDomain = try NormalisedURLDomain.normaliseUrlDomainOrThrowError(input: apiDomain) - - guard let apiUrlObj: URL = URL(string: _apiDomain), let apiHostName: String = apiUrlObj.host else { + var apiDomainAndInputDomainMatch = false + if !apiDomain.isEmpty { + let normalizedApiDomain = try NormalisedURLDomain.normaliseUrlDomainOrThrowError(input: apiDomain) + guard let apiUrlObj = URL(string: normalizedApiDomain), let apiHostName = apiUrlObj.host else { throw SDKFailableError.failableError } - - return domain == (apiUrlObj.port == nil ? apiHostName : apiHostName + ":" + "\(apiUrlObj.port!)") + apiDomainAndInputDomainMatch = domain == apiHostName + } + + if cookieDomain == nil || apiDomainAndInputDomainMatch { + // even if cookieDomain isn't undefined, if there is an exact match + // of api domain, ignoring the port, we return true + return apiDomainAndInputDomainMatch } else { - var normalisedCookieDomain = try NormalisedInputType.normaliseSessionScopeOrThrowError(sessionScope: cookieDomain!) - - if cookieDomain!.split(separator: ":").count > 1 { - let portString: String = String(cookieDomain!.split(separator: ":")[cookieDomain!.split(separator: ":").count - 1]) - - if portString.isNumeric { - normalisedCookieDomain = normalisedCookieDomain + ":" + portString - domain = urlObj.port == nil ? domain : domain + ":" + "\(urlObj.port!)" - } - } - - if cookieDomain!.starts(with: ".") { - return ("." + domain).hasSuffix(normalisedCookieDomain) - } else { - return domain == normalisedCookieDomain + let normalisedSessionDomain = try NormalisedInputType.normaliseSessionScopeOrThrowError(sessionScope: cookieDomain!) + // Using the matchesDomainOrSubdomain function to determine match + return matchesDomainOrSubdomain(domain: domain, str: normalisedSessionDomain) + } + } + + private static func matchesDomainOrSubdomain(domain: String, str: String) -> Bool { + let parts = domain.split(separator: ".").map(String.init) + + for i in 0.. Bool { diff --git a/SuperTokensIOS/Classes/Version.swift b/SuperTokensIOS/Classes/Version.swift index 412f2bd..0755416 100644 --- a/SuperTokensIOS/Classes/Version.swift +++ b/SuperTokensIOS/Classes/Version.swift @@ -9,5 +9,5 @@ import Foundation internal class Version { static let supported_fdi: [String] = ["1.16", "1.17", "1.18", "1.19"] - static let sdkVersion = "0.2.7" + static let sdkVersion = "0.3.0" } diff --git a/testHelpers/testapp/Tests/config.swift b/testHelpers/testapp/Tests/config.swift index 3c8a5bc..788004c 100644 --- a/testHelpers/testapp/Tests/config.swift +++ b/testHelpers/testapp/Tests/config.swift @@ -21,6 +21,9 @@ class ConfigTests: XCTestCase { ); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3000", apiDomain: "localhost:3000", cookieDomain: nil)); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://localhost:3000", apiDomain: "https://localhost:3000", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://localhost:3000", apiDomain: "https://localhost:3001", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost:3000", apiDomain: "http://localhost:3001", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3000", apiDomain: "localhost:3001", cookieDomain: nil)); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost:3000", apiDomain: "http://localhost:3000", cookieDomain: nil)); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3000", apiDomain: "https://localhost:3000", cookieDomain: nil)); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost", apiDomain: "https://localhost", cookieDomain: nil)); @@ -31,19 +34,27 @@ class ConfigTests: XCTestCase { XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "127.0.0.1:3000", apiDomain: "https://127.0.0.1:3000", cookieDomain: nil)); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://127.0.0.1:3000", apiDomain: "https://127.0.0.1:3000", cookieDomain: nil)); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://127.0.0.1", apiDomain: "https://127.0.0.1", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost.org", apiDomain: "localhost.org", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost.org", apiDomain: "http://localhost.org", cookieDomain: nil)); // true cases with cookieDomain XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "api.example.com", apiDomain: "", cookieDomain: "api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://api.example.com", apiDomain: "", cookieDomain: "http://api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "api.example.com", apiDomain: "", cookieDomain: ".example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "api.example.com", apiDomain: "", cookieDomain: "example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "", cookieDomain: "http://api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "", cookieDomain: "https://api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: ".sub.api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: "sub.api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: ".api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: "api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: ".example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: "example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: ".example.com:3000")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: ".example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: "https://sub.api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com:3000", apiDomain: "", cookieDomain: ".api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com:3000", apiDomain: "", cookieDomain: "api.example.com")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3000", apiDomain: "", cookieDomain: "localhost:3000")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://localhost:3000", apiDomain: "", cookieDomain: ".localhost:3000")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost", apiDomain: "", cookieDomain: "localhost")); @@ -59,27 +70,46 @@ class ConfigTests: XCTestCase { XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub1.api.example.co.uk:3000", apiDomain: "", cookieDomain: ".api.example.co.uk")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.co.uk:3000", apiDomain: "", cookieDomain: ".api.example.co.uk")); XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.co.uk:3000", apiDomain: "", cookieDomain: "api.example.co.uk")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "", cookieDomain: "example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: ".sub.api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: "sub.api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: "api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com", apiDomain: "", cookieDomain: "example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: "example.com:3000")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "", cookieDomain: "api.example.com")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3000", apiDomain: "localhost:8080", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3001", apiDomain: "localhost", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com:3002", apiDomain: "https://api.example.com:3001", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost.org", apiDomain: "localhost.org:2000", cookieDomain: nil)); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost.org", apiDomain: "localhost", cookieDomain: "localhost.org")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost", apiDomain: "localhost", cookieDomain: "localhost.org")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost", apiDomain: "", cookieDomain: "localhost:8080")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://localhost:80", apiDomain: "", cookieDomain: "localhost:8080")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "localhost:3000", apiDomain: "", cookieDomain: "localhost:8080")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: ".example.com:3001")); + XCTAssertTrue(try Utils.shouldDoInterception(toCheckURL: "http://127.0.0.1:3000", apiDomain: "", cookieDomain: "https://127.0.0.1:3010")); // false cases with api - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "localhost:3001", apiDomain: "localhost:3000", cookieDomain: nil))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "localhost:3001", apiDomain: "example.com", cookieDomain: nil))); - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "localhost:3001", apiDomain: "localhost", cookieDomain: nil))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "localhost", apiDomain: "localhost.org", cookieDomain: nil))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "google.com", apiDomain: "localhost.org", cookieDomain: nil))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "http://google.com", apiDomain: "localhost.org", cookieDomain: nil))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://google.com", apiDomain: "localhost.org", cookieDomain: nil))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://google.com:8080", apiDomain: "localhost.org", cookieDomain: nil))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "https://a.api.example.com:3000", cookieDomain: nil))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://example.com", apiDomain: "https://api.example.com", cookieDomain: nil))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "https://a.api.example.com", cookieDomain: nil))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com", apiDomain: "https://example.com", cookieDomain: nil))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://example.com:3001", apiDomain: "https://api.example.com:3001", cookieDomain: nil))); - XCTAssertTrue( - !(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com:3002", apiDomain: "https://api.example.com:3001", cookieDomain: nil)) - ); // false cases with cookieDomain - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: ".example.com:3001"))); - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: "example.com"))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "localhost", apiDomain: "", cookieDomain: "localhost.org"))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "google.com", apiDomain: "", cookieDomain: "localhost.org"))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "http://google.com", apiDomain: "", cookieDomain: "localhost.org"))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://google.com", apiDomain: "", cookieDomain: "localhost.org"))); + XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://google.com:8080", apiDomain: "", cookieDomain: "localhost.org"))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://api.example.com:3000", apiDomain: "", cookieDomain: ".a.api.example.com"))); XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.com:3000", apiDomain: "", cookieDomain: "localhost"))); - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "http://127.0.0.1:3000", apiDomain: "", cookieDomain: "https://127.0.0.1:3010"))); - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.co.uk:3000", apiDomain: "", cookieDomain: "api.example.co.uk"))); - XCTAssertTrue(!(try Utils.shouldDoInterception(toCheckURL: "https://sub.api.example.co.uk", apiDomain: "", cookieDomain: "api.example.co.uk"))); // errors in input do {