Skip to content
2 changes: 1 addition & 1 deletion app-apple/Passepartout/App/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class AppDelegate: NSObject {
func configure(with uiConfiguring: AppLibraryConfiguring?) {
context.userPreferences.applyAppearance()
uiConfiguring?.configure()
debugLocalStoreStats()
// debugLocalStoreStats()
}
}

Expand Down
30 changes: 28 additions & 2 deletions app-apple/Passepartout/App/Context/AppContext+Production.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,34 @@ extension AppContext {
)
let backupProfileRepository: ProfileRepository? = nil
#else
let tunnelStrategy = appConfiguration.newNETunnelStrategy(ctx, coder: registry)
let mainProfileRepository = NEProfileRepository(repository: tunnelStrategy)
let mainProfileRepository: ProfileRepository
let tunnelStrategy: TunnelObservableStrategy
if distributionTarget.supportsAppGroups {
let keychain = AppleKeychain(
ctx,
group: appConfiguration.bundle.bundleString(for: .keychainGroupId)
)
let keychainRepository = KeychainProfileRepository(
keychain: keychain,
coder: registry,
label: appConfiguration.newKeychainTitle()
)
let newStrategy = appConfiguration.newNETunnelStrategy(
ctx,
coder: registry,
source: keychainRepository.eventsPublisher
)
mainProfileRepository = keychainRepository
tunnelStrategy = newStrategy
} else {
let legacyStrategy = appConfiguration.legacyNETunnelStrategy(
ctx,
coder: registry
)
let neRepository = NEProfileRepository(repository: legacyStrategy)
mainProfileRepository = neRepository
tunnelStrategy = legacyStrategy
}
let backupProfileRepository = appConfiguration.newBackupProfileRepositoryV2(
encoder: appEncoder,
model: cdRemoteModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ extension TunnelContext {

// Decode profile from NE provider
do {
let decoder = appConfiguration.newNEProtocolCoder(.global, coder: registry)
let decoder = appConfiguration.newNEProtocolCoder(.global, coder: registry, legacy: false)
originalProfile = try Profile(withNEProvider: neProvider, decoder: decoder)
let resolvedProfile = try registry.resolvedProfile(originalProfile)
let processor = appConfiguration.newTunnelProcessor()
Expand Down
8 changes: 8 additions & 0 deletions app-apple/Sources/AppLibrary/Observables/AppContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,13 @@ private extension AppContext {
await iapManager.reloadReceipt()
didLoadReceiptDate = Date()
}

// Re-fetch local profiles to sync with external changes
do {
try await profileManager.refreshLocalProfiles()
} catch {
pspLog(.core, .error, "Unable to refresh local profiles: \(error)")
}
}
await pendingTask?.value
pendingTask = nil
Expand Down Expand Up @@ -381,6 +388,7 @@ private extension AppContext {
do {
try await onLaunch()
} catch {
pspLog(.core, .fault, "Unable to launch: \(error)")
launchTask = nil // Redo the launch task.
throw ABI.AppError.couldNotLaunch(reason: error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ extension ABI.AppConfiguration {
)
}

public func newFileProfileRepository(path: String) throws -> ProfileRepository {
try FileProfileRepository(
directoryURL: URL(filePath: path, directoryHint: .isDirectory)
)
}

public func newIAPManager(
inAppHelper: InAppHelper,
receiptReader: UserInAppReceiptReader,
Expand Down Expand Up @@ -380,38 +374,70 @@ extension ABI.AppConfiguration {
StoreKitReceiptReader(modeBlock: modeBlock)
}

public func newKeychainTitle() -> @Sendable (Profile) -> String {
{
String(format: constants.tunnel.profileTitleFormat, $0.name)
}
}

public func newLogFormatter() -> LogFormatter? {
FoundationLogFormatter(
dateFormat: constants.log.formatter.timestamp,
messageFormat: constants.log.formatter.message
)
}

public func newNEProtocolCoder(_ ctx: PartoutLoggerContext, coder: ProfileCoder) -> NEProtocolCoder {
public func newNEProtocolCoder(
_ ctx: PartoutLoggerContext,
coder: ProfileCoder,
legacy: Bool
) -> NEProtocolCoder {
let tunnelIdentifier = bundle.bundleString(for: .tunnelId)
if bundle.distributionTarget.supportsAppGroups {
return KeychainNEProtocolCoder(
ctx,
tunnelBundleIdentifier: tunnelIdentifier,
coder: coder,
keychain: AppleKeychain(ctx, group: bundle.bundleString(for: .keychainGroupId))
keychain: AppleKeychain(ctx, group: bundle.bundleString(for: .keychainGroupId)),
legacyOptions: legacy ? .init(title: newKeychainTitle()) : nil
)
} else {
return ProviderNEProtocolCoder(
ctx,
tunnelBundleIdentifier: tunnelIdentifier,
coder: coder
coder: coder,
uid: Int(getuid())
)
}
}

public func newNETunnelStrategy(_ ctx: PartoutLoggerContext, coder: ProfileCoder) -> NETunnelStrategy {
NETunnelStrategy(
public func legacyNETunnelStrategy(
_ ctx: PartoutLoggerContext,
coder: ProfileCoder
) -> LegacyNETunnelStrategy {
let bundleIdentifier = bundle.bundleString(for: .tunnelId)
let protocolCoder = newNEProtocolCoder(ctx, coder: coder, legacy: true)
return LegacyNETunnelStrategy(
ctx,
bundleIdentifier: bundleIdentifier,
coder: protocolCoder
)
}

public func newNETunnelStrategy(
_ ctx: PartoutLoggerContext,
coder: ProfileCoder,
source: AsyncStream<ProfilesEvent>
) -> NETunnelStrategy {
let bundleIdentifier = bundle.bundleString(for: .tunnelId)
let protocolCoder = newNEProtocolCoder(ctx, coder: coder, legacy: false)
return NETunnelStrategy(
ctx,
bundleIdentifier: bundle.bundleString(for: .tunnelId),
coder: newNEProtocolCoder(ctx, coder: coder),
title: {
String(format: constants.tunnel.profileTitleFormat, $0.name)
bundleIdentifier: bundleIdentifier,
source: source,
coder: protocolCoder,
fingerprint: {
($0.attributes.fingerprint ?? $0.id)?.uuidString
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ extension ProfileManager {
self.isRemoteImportingEnabled = isRemoteImportingEnabled
}

@discardableResult
public func refreshLocalProfiles() async throws -> [Profile] {
try await repository.fetchProfiles()
}

public func save(_ originalProfile: Profile, isLocal: Bool = false, remotelyShared: Bool? = nil) async throws {
let profile: Profile
if isLocal {
Expand Down
Loading