Skip to content

Commit

Permalink
[_]: Fix issue while refreshing tokens, disable ATS
Browse files Browse the repository at this point in the history
  • Loading branch information
PixoDev committed Sep 5, 2024
1 parent 8cc0fcd commit a4ef213
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 73 deletions.
12 changes: 6 additions & 6 deletions InternxtDesktop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2104,7 +2104,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 66;
CURRENT_PROJECT_VERSION = 67;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
Expand All @@ -2118,7 +2118,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.4.1;
MARKETING_VERSION = 2.4.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
"OTHER_CFLAGS[arch=*]" = (
Expand Down Expand Up @@ -2242,7 +2242,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 66;
CURRENT_PROJECT_VERSION = 67;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand All @@ -2262,7 +2262,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.4.1;
MARKETING_VERSION = 2.4.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -2310,7 +2310,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 66;
CURRENT_PROJECT_VERSION = 67;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
Expand All @@ -2324,7 +2324,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.4.1;
MARKETING_VERSION = 2.4.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
"OTHER_CFLAGS[arch=*]" = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"location" : "https://github.com/internxt/swift-core",
"state" : {
"branch" : "main",
"revision" : "6d23db5c0b727d047b850bb81c62bb3d17b84939"
"revision" : "8a9eee24a9ec8b6650cdfd290530fc8f438fe712"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array/>
</plist>
3 changes: 2 additions & 1 deletion InternxtDesktop/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,8 @@ class AppDelegate: NSObject, NSApplicationDelegate , PKPushRegistryDelegate {

private func checkRefreshToken(){
do {
if try authManager.needRefreshToken(){
let refreshTokenCheckResult = try authManager.needRefreshToken()
if refreshTokenCheckResult.needsRefresh {
Task {await self.refreshTokens()}
}
}
Expand Down
5 changes: 5 additions & 0 deletions InternxtDesktop/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
</array>
</dict>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>SUAutomaticallyUpdate</key>
<true/>
<key>SUEnableAutomaticChecks</key>
Expand Down
91 changes: 77 additions & 14 deletions InternxtDesktop/Services/Auth/AuthManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ import Foundation
import InternxtSwiftCore
import os.log


struct NeedsTokenRefreshResult {
var needsRefresh: Bool
var authTokenCreationDate: Date
var legacyAuthTokenCreationDate: Date
var authTokenDaysUntilExpiration: Int
var legacyAuthTokenDaysUntilExpiration: Int
}
class AuthManager: ObservableObject {
let logger = Logger(subsystem: "com.internxt", category: "AuthManager")
@Published public var isLoggedIn = false
@Published public var user: DriveUser? = nil
public let config = ConfigLoader()
public let cryptoUtils = CryptoUtils()
private let REFRESH_TOKEN_DEADLINE = 3
private let REFRESH_TOKEN_DEADLINE = 5
init() {
self.isLoggedIn = checkIsLoggedIn()
self.user = config.getUser()
Expand Down Expand Up @@ -58,11 +66,15 @@ class AuthManager: ObservableObject {
}

func refreshTokens() async throws {
guard let legacyAuthToken = config.getLegacyAuthToken() else {
throw AuthError.LegacyAuthTokenNotInConfig
guard let authToken = config.getAuthToken() else {
throw AuthError.AuthTokenNotInConfig
}
let refreshUserResponse = try await APIFactory.Drive.refreshUser(currentAuthToken: legacyAuthToken )
try config.setLegacyAuthToken(legacyAuthToken: refreshUserResponse.token)

let newTokensResponse = try await APIFactory.DriveNew.refreshTokens(currentAuthToken: authToken )


try config.setLegacyAuthToken(legacyAuthToken: newTokensResponse.token)
try config.setAuthToken(authToken: newTokensResponse.newToken)
}

func storeAuthDetails(plainMnemonic: String, authToken: String, legacyAuthToken: String) throws {
Expand Down Expand Up @@ -149,25 +161,76 @@ class AuthManager: ObservableObject {
return true
}

func needRefreshToken() throws -> Bool {

func needRefreshToken() throws -> NeedsTokenRefreshResult {
guard let legacyAuthToken = config.getLegacyAuthToken() else {
throw AuthError.LegacyAuthTokenNotInConfig
}

guard let authToken = config.getAuthToken() else {
throw AuthError.AuthTokenNotInConfig
}

let responseDecodeLegacy = try JWTDecoder.decode(jwtToken: legacyAuthToken)
let decodedLegacyAuthToken = try JWTDecoder.decode(jwtToken: legacyAuthToken)
let decodedAuthToken = try JWTDecoder.decode(jwtToken: authToken)

guard let expTimestamp = responseDecodeLegacy["exp"] as? Int else {
guard let authTokenExpirationTimestamp = decodedAuthToken["exp"] as? Int else {
throw AuthError.InvalidTokenExp
}

let expDate = Date(timeIntervalSince1970: TimeInterval(expTimestamp))
let currentDate = Date()

guard let daysUntilExpiration = currentDate.daysUntil(expDate) else {
return true
guard let authTokenCreationTimestamp = decodedAuthToken["iat"] as? Int else {
throw AuthError.InvalidTokenIat
}


guard let legacyAuthTokenExpirationTimestamp = decodedLegacyAuthToken["exp"] as? Int else {
throw AuthError.InvalidTokenExp
}

guard let legacyAuthTokenCreationTimestamp = decodedLegacyAuthToken["iat"] as? Int else {
throw AuthError.InvalidTokenIat
}

let authTokenExpirationDate = Date(timeIntervalSince1970: TimeInterval(authTokenExpirationTimestamp))
let authTokenCreationDate = Date(timeIntervalSince1970: TimeInterval(authTokenCreationTimestamp))

let legacyAuthTokenExpirationDate = Date(timeIntervalSince1970: TimeInterval(legacyAuthTokenExpirationTimestamp))
let legacyAuthTokenCreationDate = Date(timeIntervalSince1970: TimeInterval(legacyAuthTokenCreationTimestamp))



let daysUntilAuthTokenExpires = Date().daysUntil(authTokenExpirationDate) ?? 1
let daysUntilLegacyAuthTokenExpires = Date().daysUntil(legacyAuthTokenExpirationDate) ?? 1

if daysUntilAuthTokenExpires <= REFRESH_TOKEN_DEADLINE {
return NeedsTokenRefreshResult(
needsRefresh: true,
authTokenCreationDate: authTokenCreationDate,
legacyAuthTokenCreationDate:legacyAuthTokenCreationDate,
authTokenDaysUntilExpiration: daysUntilAuthTokenExpires,
legacyAuthTokenDaysUntilExpiration: daysUntilLegacyAuthTokenExpires
)
}

if daysUntilLegacyAuthTokenExpires <= REFRESH_TOKEN_DEADLINE {
return NeedsTokenRefreshResult(
needsRefresh: true,
authTokenCreationDate: authTokenCreationDate,
legacyAuthTokenCreationDate:legacyAuthTokenCreationDate,
authTokenDaysUntilExpiration: daysUntilAuthTokenExpires,
legacyAuthTokenDaysUntilExpiration: daysUntilLegacyAuthTokenExpires
)
}

return daysUntilExpiration <= REFRESH_TOKEN_DEADLINE


return NeedsTokenRefreshResult(
needsRefresh: false,
authTokenCreationDate: authTokenCreationDate,
legacyAuthTokenCreationDate:legacyAuthTokenCreationDate,
authTokenDaysUntilExpiration: daysUntilAuthTokenExpires,
legacyAuthTokenDaysUntilExpiration: daysUntilLegacyAuthTokenExpires
)
}
}

Expand Down
2 changes: 2 additions & 0 deletions Shared/Errors/Generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ enum AppError: Error {
enum AuthError: Error {
case UnableToRefreshToken
case LegacyAuthTokenNotInConfig
case AuthTokenNotInConfig
case noUserFound
case InvalidTokenExp
case InvalidTokenIat
}
2 changes: 1 addition & 1 deletion Shared/Services/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class AppSettings: ObservableObject {
}

@Published public var selectedLanguage: Languages = .en
@Published public var selectedBackupFrequency: BackupFrequencyEnum = .daily
@Published public var selectedBackupFrequency: BackupFrequencyEnum = .manually

private var bag = Set<AnyCancellable>()

Expand Down
4 changes: 2 additions & 2 deletions Shared/Services/Backups/BackupsService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ class BackupsService: ObservableObject {
logger.info("Going to backup folders \(self.foldersToBackup)")

if self.foldersToBackup.isEmpty {
logger.error("Foldernames are empty")
throw BackupError.emptyFolders
logger.error("There are no folders selected for backup, cannot start one.")
return
}

DispatchQueue.main.sync {
Expand Down
3 changes: 1 addition & 2 deletions Shared/Services/ConfigLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ enum ConfigLoaderError: Error {
public let INTERNXT_GROUP_NAME = "JR4S3SY396.group.internxt.desktop"

public var loadedConfig: JSONConfig? = nil
public var loadedLegacyAuthToken: String? = nil
public var loadedAuthToken: String? = nil

public struct ConfigLoader {
static let shared: ConfigLoader = ConfigLoader()

Expand Down
2 changes: 2 additions & 0 deletions Shared/Utils/APIFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func getVersion() -> String {

return "\(version).\(buildNumber)"
}


struct APIFactory {


Expand Down
62 changes: 32 additions & 30 deletions SyncExtension/FileProviderExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile
let user: DriveUser
let mnemonic: String
let authManager: AuthManager
let refreshTokensIntervalTimer: AnyCancellable
let activityManager: ActivityManager
let realtime: RealtimeService?
private let driveNewAPI: DriveAPI = APIFactory.DriveNew
Expand Down Expand Up @@ -57,29 +56,6 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile
ErrorUtils.fatal("Cannot find user in auth manager, cannot initialize extension")
}


self.refreshTokensIntervalTimer = Timer.publish(every: 15, on:.main, in: .common)
.autoconnect()
.sink(
receiveValue: {_ in
Task {
do {
if try authManager.needRefreshToken(){
try await authManager.refreshTokens()
logger.info("Tokens refreshed successfully")
}

} catch {
error.reportToSentry()
logger.error(["Failed to refresh tokens from sync extension", error])
}

}
})




ErrorUtils.identify(email: user.email, uuid: user.uuid)

self.user = user
Expand Down Expand Up @@ -133,7 +109,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile
pushRegistry = PKPushRegistry(queue: nil)
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = [.fileProvider]

self.refreshAuthTokensIfNeeded()
}


Expand All @@ -157,10 +133,35 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile

func invalidate() {
fileProviderItemActions.clean()
self.refreshTokensIntervalTimer.cancel()
}

func refreshAuthTokensIfNeeded() -> Void {
Task {
do {
let refreshTokenCheckResult = try authManager.needRefreshToken()
logger.info("Auth token: Created at \(refreshTokenCheckResult.authTokenCreationDate), days until expiration: \(refreshTokenCheckResult.authTokenDaysUntilExpiration)")

logger.info("Legacy auth token: Created at \(refreshTokenCheckResult.legacyAuthTokenCreationDate), days until expiration: \(refreshTokenCheckResult.legacyAuthTokenDaysUntilExpiration)")


if refreshTokenCheckResult.needsRefresh {
try await authManager.refreshTokens()
logger.info("Auth tokens refreshed successfully")
} else {
logger.info("Auth tokens doesn't need a refresh")

}
} catch {
logger.error(["Cannot refresh tokens, something went wrong", error])
error.reportToSentry()
}

}

}

func item(for identifier: NSFileProviderItemIdentifier, request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) -> Progress {
refreshAuthTokensIfNeeded()
// resolve the given identifier to a record in the model

logger.info("Getting item metadata for \(identifier.rawValue)")
Expand Down Expand Up @@ -202,7 +203,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile


func fetchContents(for itemIdentifier: NSFileProviderItemIdentifier, version requestedVersion: NSFileProviderItemVersion?, request: NSFileProviderRequest, completionHandler: @escaping (URL?, NSFileProviderItem?, Error?) -> Void) -> Progress {

refreshAuthTokensIfNeeded()
let encryptedFileDestinationURL = makeTemporaryURL("encrypt", "enc")
let destinationURL = makeTemporaryURL("plain")

Expand Down Expand Up @@ -231,7 +232,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile


func createItem(basedOn itemTemplate: NSFileProviderItem, fields: NSFileProviderItemFields, contents url: URL?, options: NSFileProviderCreateItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {

refreshAuthTokensIfNeeded()
// This is a Microsoft Office tmp file, we don't want to sync this
if(itemTemplate.filename.hasPrefix("~$")) {
logger.info("⚠️ Microsoft Office tmp file detected with name: \(itemTemplate.filename)")
Expand Down Expand Up @@ -294,7 +295,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile

func modifyItem(_ item: NSFileProviderItem, baseVersion version: NSFileProviderItemVersion, changedFields: NSFileProviderItemFields, contents newContents: URL?, options: NSFileProviderModifyItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {


refreshAuthTokensIfNeeded()
if changedFields.contains(.extendedAttributes) {
logger.info("Checking extended attributes \(item.filename)")
let filename = item.filename as NSString
Expand Down Expand Up @@ -411,7 +412,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile
}

func performAction(identifier actionIdentifier: NSFileProviderExtensionActionIdentifier, onItemsWithIdentifiers itemIdentifiers: [NSFileProviderItemIdentifier], completionHandler: @escaping (Error?) -> Void) -> Progress {

refreshAuthTokensIfNeeded()
if actionIdentifier == FileProviderItemActionsManager.RefreshContent {
logger.info("User requested to refresh content, signalling enumerator...")
manager.signalEnumerator(for: .workingSet, completionHandler: {error in
Expand Down Expand Up @@ -489,6 +490,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NSFile
didUpdate credentials: PKPushCredentials,
for type: PKPushType
){
refreshAuthTokensIfNeeded()
logger.info("📍 Got Device token for push notifications from SyncExtension")
let deviceToken = credentials.token

Expand Down
Loading

0 comments on commit a4ef213

Please sign in to comment.