From c7eca68a24a5627de82544144b481d0dae81770b Mon Sep 17 00:00:00 2001 From: Sammy Khamis Date: Wed, 18 Oct 2023 21:28:41 -1000 Subject: [PATCH] Refactor FXIOS-7214 [v121] Remove unused FxA files (#16922) --- Account/SyncAuthState.swift | 189 ------------------ Client.xcodeproj/project.pbxproj | 8 - .../Main/AppSettingsTableViewController.swift | 1 - .../ForgetSyncAuthStateDebugSetting.swift | 18 -- Client/Telemetry/TelemetryWrapper.swift | 15 -- RustFxA/RustFirefoxAccounts.swift | 21 -- Shared/Bytes.swift | 18 -- Tests/AccountTests/Push/AutopushTests.swift | 3 +- Tests/SyncTests/CryptoTests.swift | 22 -- 9 files changed, 2 insertions(+), 293 deletions(-) delete mode 100644 Account/SyncAuthState.swift delete mode 100644 Client/Frontend/Settings/Main/Debug/ForgetSyncAuthStateDebugSetting.swift diff --git a/Account/SyncAuthState.swift b/Account/SyncAuthState.swift deleted file mode 100644 index 8bb14714734e..000000000000 --- a/Account/SyncAuthState.swift +++ /dev/null @@ -1,189 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import Foundation -import Common -import MozillaAppServices -import Shared -import SwiftyJSON - -public let FxAClientErrorDomain = "org.mozilla.fxa.error" -public let FxAClientUnknownError = NSError( - domain: FxAClientErrorDomain, - code: 999, - userInfo: [NSLocalizedDescriptionKey: "Invalid server response"]) - -public struct FxAccountRemoteError { - static let AttemptToOperateOnAnUnverifiedAccount: Int32 = 104 - static let InvalidAuthenticationToken: Int32 = 110 - static let EndpointIsNoLongerSupported: Int32 = 116 - static let IncorrectLoginMethodForThisAccount: Int32 = 117 - static let IncorrectKeyRetrievalMethodForThisAccount: Int32 = 118 - static let IncorrectAPIVersionForThisAccount: Int32 = 119 - static let UnknownDevice: Int32 = 123 - static let DeviceSessionConflict: Int32 = 124 - static let UnknownError: Int32 = 999 -} - -public enum FxAClientError: Error, CustomStringConvertible { - case remote(RemoteError) - case local(NSError) - - public var description: String { - switch self { - case .remote(let err): return "FxA remote error: \(err)" - case .local(let err): return "FxA local error: \(err)" - } - } -} - -public struct RemoteError { - let code: Int32 - let errno: Int32 - let error: String? - let message: String? - let info: String? - - var isUpgradeRequired: Bool { - return errno == FxAccountRemoteError.EndpointIsNoLongerSupported - || errno == FxAccountRemoteError.IncorrectLoginMethodForThisAccount - || errno == FxAccountRemoteError.IncorrectKeyRetrievalMethodForThisAccount - || errno == FxAccountRemoteError.IncorrectAPIVersionForThisAccount - } - - var isInvalidAuthentication: Bool { - return code == 401 - } - - var isUnverified: Bool { - return errno == FxAccountRemoteError.AttemptToOperateOnAnUnverifiedAccount - } -} - -private let CurrentSyncAuthStateCacheVersion = 1 - -public struct SyncAuthStateCache { - let token: TokenServerToken - let forKey: Data - let expiresAt: Timestamp -} - -public protocol SyncAuthState { - func invalidate() - func token(_ now: Timestamp, canBeExpired: Bool) -> Deferred> - var enginesEnablements: [String: Bool]? { get set } - var clientName: String? { get set } -} - -public func syncAuthStateCachefromJSON(_ json: JSON) -> SyncAuthStateCache? { - if let version = json["version"].int { - if version != CurrentSyncAuthStateCacheVersion { - DefaultLogger.shared.log("Sync Auth State Cache is wrong version; dropping.", - level: .warning, - category: .sync) - return nil - } - if let token = TokenServerToken.fromJSON(json["token"]), - let forKey = json["forKey"].string?.hexDecodedData, - let expiresAt = json["expiresAt"].int64 { - return SyncAuthStateCache(token: token, forKey: forKey, expiresAt: Timestamp(expiresAt)) - } - } - return nil -} - -extension SyncAuthStateCache: JSONLiteralConvertible { - public func asJSON() -> JSON { - return JSON([ - "version": CurrentSyncAuthStateCacheVersion, - "token": token.asJSON(), - "forKey": forKey.hexEncodedString, - "expiresAt": NSNumber(value: expiresAt), - ] as NSDictionary) - } -} - -open class FirefoxAccountSyncAuthState: SyncAuthState { - private var logger: Logger - fileprivate let cache: KeychainCache - public var enginesEnablements: [String: Bool]? - public var clientName: String? - - init(cache: KeychainCache, - logger: Logger = DefaultLogger.shared) { - self.cache = cache - self.logger = logger - } - - // If a token gives you a 401, invalidate it and request a new one. - open func invalidate() { - logger.log("Invalidating cached token server token.", - level: .info, - category: .sync) - self.cache.value = nil - } - - open func token(_ now: Timestamp, canBeExpired: Bool) -> Deferred> { - if let value = cache.value { - // Give ourselves some room to do work. - let isExpired = value.expiresAt < now + 5 * OneMinuteInMilliseconds - if canBeExpired { - if isExpired { - logger.log("Returning cached expired token.", - level: .info, - category: .sync) - } else { - logger.log("Returning cached token, which should be valid.", - level: .info, - category: .sync) - } - return deferMaybe((token: value.token, forKey: value.forKey)) - } - - if !isExpired { - logger.log("Returning cached token, which should be valid.", - level: .info, - category: .sync) - return deferMaybe((token: value.token, forKey: value.forKey)) - } - } - - let deferred = Deferred>() - - RustFirefoxAccounts.shared.accountManager.uponQueue(.main) { accountManager in - accountManager.getTokenServerEndpointURL { result in - guard case .success(let tokenServerEndpointURL) = result else { - deferred.fill(Maybe(failure: FxAClientError.local(NSError()))) - return - } - - let client = TokenServerClient(url: tokenServerEndpointURL) - accountManager.getAccessToken(scope: OAuthScope.oldSync) { res in - switch res { - case .failure(let err): - deferred.fill(Maybe(failure: err as MaybeErrorType)) - case .success(let accessToken): - self.logger.log("Fetching token server token.", - level: .debug, - category: .sync) - client.token(token: accessToken.token, kid: accessToken.key!.kid).upon { result in - guard let token = result.successValue else { - deferred.fill(Maybe(failure: result.failureValue!)) - return - } - let kSync = Bytes.base64urlSafeDecodedData(accessToken.key!.k)! - let newCache = SyncAuthStateCache(token: token, forKey: kSync, expiresAt: now + 1000 * token.durationInSeconds) - self.logger.log("Fetched token server token! Token expires at \(newCache.expiresAt).", - level: .debug, - category: .sync) - self.cache.value = newCache - deferred.fill(Maybe(success: (token: token, forKey: kSync))) - } - } - } - } - } - return deferred - } -} diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 5109c06f0849..ab71a68ea4d2 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -225,7 +225,6 @@ 2FCAE2781ABB531100877008 /* Visit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE25C1ABB531100877008 /* Visit.swift */; }; 2FCAE2841ABB533A00877008 /* MockFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2791ABB533A00877008 /* MockFiles.swift */; }; 2FDB10931A9FBEC5006CF312 /* PrefsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDB10921A9FBEC5006CF312 /* PrefsTests.swift */; }; - 2FDBCF611ABFC9DE00AFF7F0 /* SyncAuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDBCF601ABFC9DE00AFF7F0 /* SyncAuthState.swift */; }; 2FDE87FE1ABB3817005317B1 /* LegacyRemoteTabsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDE87FD1ABB3817005317B1 /* LegacyRemoteTabsPanel.swift */; }; 318FB6EB1DB5600D0004E40F /* SQLiteHistoryFactories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318FB6EA1DB5600D0004E40F /* SQLiteHistoryFactories.swift */; }; 31ADB5DA1E58CEC300E87909 /* ClipboardBarDisplayHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31ADB5D91E58CEC300E87909 /* ClipboardBarDisplayHandler.swift */; }; @@ -591,7 +590,6 @@ 8A3EF7FD2A2FCFAC00796E3A /* AppReviewPromptSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF7FC2A2FCFAC00796E3A /* AppReviewPromptSetting.swift */; }; 8A3EF7FF2A2FCFBB00796E3A /* ChangeToChinaSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF7FE2A2FCFBB00796E3A /* ChangeToChinaSetting.swift */; }; 8A3EF8012A2FCFC900796E3A /* FasterInactiveTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF8002A2FCFC900796E3A /* FasterInactiveTabs.swift */; }; - 8A3EF8052A2FCFE500796E3A /* ForgetSyncAuthStateDebugSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF8042A2FCFE500796E3A /* ForgetSyncAuthStateDebugSetting.swift */; }; 8A3EF8072A2FCFF700796E3A /* SentryIDSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF8062A2FCFF700796E3A /* SentryIDSetting.swift */; }; 8A3EF8092A2FD02B00796E3A /* ExperimentsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF8082A2FD02B00796E3A /* ExperimentsSettings.swift */; }; 8A3EF80D2A2FD04D00796E3A /* ResetWallpaperOnboardingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3EF80C2A2FD04D00796E3A /* ResetWallpaperOnboardingPage.swift */; }; @@ -2381,7 +2379,6 @@ 2FCAE33D1ABB5F1800877008 /* Storage-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Storage-Bridging-Header.h"; sourceTree = ""; }; 2FCF4713ABA14D85F70567AC /* kk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kk; path = kk.lproj/Today.strings; sourceTree = ""; }; 2FDB10921A9FBEC5006CF312 /* PrefsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefsTests.swift; sourceTree = ""; }; - 2FDBCF601ABFC9DE00AFF7F0 /* SyncAuthState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncAuthState.swift; sourceTree = ""; }; 2FDE46BCA5E27EF7DC02CE20 /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = sq.lproj/FindInPage.strings; sourceTree = ""; }; 2FDE87FD1ABB3817005317B1 /* LegacyRemoteTabsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyRemoteTabsPanel.swift; sourceTree = ""; }; 2FEBABAE1AB3659000DB5728 /* ResultTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = ""; }; @@ -4974,7 +4971,6 @@ 8A3EF7FC2A2FCFAC00796E3A /* AppReviewPromptSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppReviewPromptSetting.swift; sourceTree = ""; }; 8A3EF7FE2A2FCFBB00796E3A /* ChangeToChinaSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeToChinaSetting.swift; sourceTree = ""; }; 8A3EF8002A2FCFC900796E3A /* FasterInactiveTabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FasterInactiveTabs.swift; sourceTree = ""; }; - 8A3EF8042A2FCFE500796E3A /* ForgetSyncAuthStateDebugSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForgetSyncAuthStateDebugSetting.swift; sourceTree = ""; }; 8A3EF8062A2FCFF700796E3A /* SentryIDSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryIDSetting.swift; sourceTree = ""; }; 8A3EF8082A2FD02B00796E3A /* ExperimentsSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperimentsSettings.swift; sourceTree = ""; }; 8A3EF80C2A2FD04D00796E3A /* ResetWallpaperOnboardingPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetWallpaperOnboardingPage.swift; sourceTree = ""; }; @@ -7590,7 +7586,6 @@ 2F14E1391ABB890800FF98DB /* Account-Bridging-Header.h */, 3905B4D41E8E7A6B0027D953 /* FxAPushMessageHandler.swift */, 2FA436271ABB8436008031D1 /* HawkHelper.swift */, - 2FDBCF601ABFC9DE00AFF7F0 /* SyncAuthState.swift */, 2FA436281ABB8436008031D1 /* TokenServerClient.swift */, 2FA435FD1ABB83B4008031D1 /* Supporting Files */, ); @@ -8354,7 +8349,6 @@ 8A3EF8002A2FCFC900796E3A /* FasterInactiveTabs.swift */, BCFF93F12AAF9688005B5B71 /* FirefoxSuggestSettings.swift */, 8A3EF7FA2A2FCF9D00796E3A /* ForceCrashSetting.swift */, - 8A3EF8042A2FCFE500796E3A /* ForgetSyncAuthStateDebugSetting.swift */, 8A3EF7EF2A2FCF3100796E3A /* HiddenSettings.swift */, 8A3EF8142A2FD08800796E3A /* OpenFiftyTabsDebugOption.swift */, 8A3EF8122A2FD07A00796E3A /* ResetContextualHints.swift */, @@ -12139,7 +12133,6 @@ EB07F860240D696000924860 /* PushNotificationSetup.swift in Sources */, C8E2E80D23D20FB3005AACE6 /* RustFirefoxAccounts.swift in Sources */, C8E2E80C23D20FB3005AACE6 /* Avatar.swift in Sources */, - 2FDBCF611ABFC9DE00AFF7F0 /* SyncAuthState.swift in Sources */, 96666D0229969F7D00A4029F /* GeneralizedImageFetcher.swift in Sources */, 45355B272A269EAC00B1EA8E /* PushConfiguration.swift in Sources */, 2FA436351ABB8436008031D1 /* TokenServerClient.swift in Sources */, @@ -12465,7 +12458,6 @@ C2D1A10D2A66C70000205DCC /* BookmarksCoordinator.swift in Sources */, 396E38F11EE0C8EC00CC180F /* FxAPushMessageHandler.swift in Sources */, 8A76B01629F6EB3900A82607 /* ScreenshotService.swift in Sources */, - 8A3EF8052A2FCFE500796E3A /* ForgetSyncAuthStateDebugSetting.swift in Sources */, E4CD9F6D1A77DD2800318571 /* ReaderModeStyleViewController.swift in Sources */, E13E9AB52AAB0FB5001A0E9D /* FakespotViewModel.swift in Sources */, 8A5D1CBD2A30DC4E005AD35C /* AccountStatusSetting.swift in Sources */, diff --git a/Client/Frontend/Settings/Main/AppSettingsTableViewController.swift b/Client/Frontend/Settings/Main/AppSettingsTableViewController.swift index 542f119e8d4e..0e2cf0fa84a6 100644 --- a/Client/Frontend/Settings/Main/AppSettingsTableViewController.swift +++ b/Client/Frontend/Settings/Main/AppSettingsTableViewController.swift @@ -313,7 +313,6 @@ class AppSettingsTableViewController: SettingsTableViewController, ExportBrowserDataSetting(settings: self), DeleteExportedDataSetting(settings: self), ForceCrashSetting(settings: self), - ForgetSyncAuthStateDebugSetting(settings: self), SwitchFakespotProduction(settings: self, settingsDelegate: self), ChangeToChinaSetting(settings: self), AppReviewPromptSetting(settings: self, settingsDelegate: self), diff --git a/Client/Frontend/Settings/Main/Debug/ForgetSyncAuthStateDebugSetting.swift b/Client/Frontend/Settings/Main/Debug/ForgetSyncAuthStateDebugSetting.swift deleted file mode 100644 index 8981b9984fd4..000000000000 --- a/Client/Frontend/Settings/Main/Debug/ForgetSyncAuthStateDebugSetting.swift +++ /dev/null @@ -1,18 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import Foundation - -class ForgetSyncAuthStateDebugSetting: HiddenSetting { - override var title: NSAttributedString? { - return NSAttributedString( - string: "Forget Sync auth state", - attributes: [NSAttributedString.Key.foregroundColor: theme.colors.textPrimary]) - } - - override func onClick(_ navigationController: UINavigationController?) { - settings.profile.rustFxA.syncAuthState.invalidate() - settings.tableView.reloadData() - } -} diff --git a/Client/Telemetry/TelemetryWrapper.swift b/Client/Telemetry/TelemetryWrapper.swift index a56258745fc2..1ec21617757d 100644 --- a/Client/Telemetry/TelemetryWrapper.swift +++ b/Client/Telemetry/TelemetryWrapper.swift @@ -177,7 +177,6 @@ class TelemetryWrapper: TelemetryWrapperProtocol, FeatureFlaggable { // Save the profile so we can record settings from it when the notification below fires. self.profile = profile - setSyncDeviceId() SponsoredTileTelemetry.setupContextId() // Register an observer to record settings and other metrics that are more appropriate to @@ -196,20 +195,6 @@ class TelemetryWrapper: TelemetryWrapperProtocol, FeatureFlaggable { ) } - // Sets hashed fxa sync device id for glean deletion ping - func setSyncDeviceId() { - // Grab our token so we can use the hashed_fxa_uid and clientGUID for deletion-request ping - guard let accountManager = RustFirefoxAccounts.shared.accountManager.peek(), - let state = accountManager.deviceConstellation()?.state(), - let clientGUID = state.localDevice?.id - else { return } - - RustFirefoxAccounts.shared.syncAuthState.token(Date.now(), canBeExpired: true) >>== { (token, _) in - let deviceId = (clientGUID + token.hashedFxAUID).sha256.hexEncodedString - GleanMetrics.Deletion.syncDeviceId.set(deviceId) - } - } - @objc func recordFinishedLaunchingPreferenceMetrics(notification: NSNotification) { guard let profile = self.profile else { return } diff --git a/RustFxA/RustFirefoxAccounts.swift b/RustFxA/RustFirefoxAccounts.swift index 2b5758aa7220..5d71b67314d9 100644 --- a/RustFxA/RustFirefoxAccounts.swift +++ b/RustFxA/RustFirefoxAccounts.swift @@ -32,7 +32,6 @@ open class RustFirefoxAccounts { public var accountManager = Deferred() private static var isInitializingAccountManager = false public var avatar: Avatar? - public let syncAuthState: SyncAuthState fileprivate static var prefs: Prefs? public let pushNotifications = PushNotificationSetup() private let logger: Logger @@ -82,19 +81,6 @@ open class RustFirefoxAccounts { return RustFirefoxAccounts.shared.accountManager } - private static let prefKeySyncAuthStateUniqueID = "PrefKeySyncAuthStateUniqueID" - private static func syncAuthStateUniqueId(prefs: Prefs?) -> String { - let id: String - let key = RustFirefoxAccounts.prefKeySyncAuthStateUniqueID - if let _id = prefs?.stringForKey(key) { - id = _id - } else { - id = UUID().uuidString - prefs?.setString(id, forKey: key) - } - return id - } - @discardableResult public static func reconfig(prefs: Prefs) -> Deferred { if isInitializingAccountManager { @@ -152,12 +138,7 @@ open class RustFirefoxAccounts { // before any Application Services component gets used. Viaduct.shared.useReqwestBackend() - let prefs = RustFirefoxAccounts.prefs self.logger = logger - let cache = KeychainCache.fromBranch("rustAccounts.syncAuthState", - withLabel: RustFirefoxAccounts.syncAuthStateUniqueId(prefs: prefs), - factory: syncAuthStateCachefromJSON) - syncAuthState = FirefoxAccountSyncAuthState(cache: cache) // Called when account is logged in for the first time, on every app start when the account is found (even if offline). NotificationCenter.default.addObserver(forName: .accountAuthenticated, object: nil, queue: .main) { [weak self] notification in @@ -226,10 +207,8 @@ open class RustFirefoxAccounts { guard let accountManager = accountManager.peek() else { return } accountManager.logout { _ in } let prefs = RustFirefoxAccounts.prefs - prefs?.removeObjectForKey(RustFirefoxAccounts.prefKeySyncAuthStateUniqueID) prefs?.removeObjectForKey(prefKeyCachedUserProfile) prefs?.removeObjectForKey(PendingAccountDisconnectedKey) - self.syncAuthState.invalidate() cachedUserProfile = nil MZKeychainWrapper.sharedClientAppContainerKeychain.removeObject(forKey: KeychainKey.apnsToken, withAccessibility: .afterFirstUnlock) } diff --git a/Shared/Bytes.swift b/Shared/Bytes.swift index 38bf9248d70e..7bc416c0d33b 100644 --- a/Shared/Bytes.swift +++ b/Shared/Bytes.swift @@ -21,24 +21,6 @@ extension Bytes { return Data(base64Encoded: b64, options: []) } - public static func base64urlSafeDecodedData(_ b64: String) -> Data? { - // Replace the URL-safe chars with their URL-unsafe variants - // https://en.wikipedia.org/wiki/Base64#Variants_summary_table - var base64 = b64 - .replacingOccurrences(of: "-", with: "+") - .replacingOccurrences(of: "_", with: "/") - - // Add padding if needed - if base64.count % 4 != 0 { - base64.append(String(repeating: "=", count: 4 - base64.count % 4)) - } - - if let data = Data(base64Encoded: base64) { - return data - } - return nil - } - /** * Turn a string of base64 characters into an NSData *without decoding*. * This is to allow HMAC to be computed of the raw base64 string. diff --git a/Tests/AccountTests/Push/AutopushTests.swift b/Tests/AccountTests/Push/AutopushTests.swift index dca44771506a..7727a854c2f6 100644 --- a/Tests/AccountTests/Push/AutopushTests.swift +++ b/Tests/AccountTests/Push/AutopushTests.swift @@ -5,7 +5,8 @@ import Foundation import XCTest import MozillaAppServices -import Account +@testable import Account +@testable import Client class AutopushTests: XCTestCase { private var mockPushManager: MockPushManager! diff --git a/Tests/SyncTests/CryptoTests.swift b/Tests/SyncTests/CryptoTests.swift index 40ff6ff38add..6a2bb7e399eb 100644 --- a/Tests/SyncTests/CryptoTests.swift +++ b/Tests/SyncTests/CryptoTests.swift @@ -43,26 +43,4 @@ c2l0cyI6W3siZGF0ZSI6MTMxOTE0OTAxMjM3MjQyNSwidHlwZSI6MX1dfQ== func testBadBase64() { XCTAssertNil(Bytes.decodeBase64(invalidB64)) } - - func testBase64DecodeUrlSafe() { - var decodedData = Bytes.base64urlSafeDecodedData("VGhpcyB3b3JrcyE") - var decodedString = String(data: decodedData!, encoding: .utf8) - XCTAssertEqual(decodedString, "This works!") - - decodedData = Bytes.base64urlSafeDecodedData("cUw4UjRRSWNRL1pzUnFPQWJlUmZjWmhpbE4vTWtzUnREYUVyTUErPQ") - decodedString = String(data: decodedData!, encoding: .utf8) - XCTAssertEqual(decodedString, "qL8R4QIcQ/ZsRqOAbeRfcZhilN/MksRtDaErMA+=") - - decodedData = Bytes.base64urlSafeDecodedData("VGhpcytzaG91bGQvd29yay1maW5l") - decodedString = String(data: decodedData!, encoding: .utf8) - XCTAssertEqual(decodedString, "This+should/work-fine") - - decodedData = Bytes.base64urlSafeDecodedData("c29tZS90b2tlbi9zZXJ2ZXIvc3R1ZmY=") - decodedString = String(data: decodedData!, encoding: .utf8) - XCTAssertEqual(decodedString, "some/token/server/stuff") - - decodedData = Bytes.base64urlSafeDecodedData("c3ViamVjdHM_X2Q") - decodedString = String(data: decodedData!, encoding: .utf8) - XCTAssertEqual(decodedString, "subjects?_d") - } }