Skip to content
Closed
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ The camera app that minds its own business.
[![CodeQL Advanced](https://github.com/SecureCamera/SecureCameraIos/actions/workflows/codeql.yml/badge.svg)](https://github.com/SecureCamera/SecureCameraIos/actions/workflows/codeql.yml)
[![codebeat badge](https://codebeat.co/badges/98126bc1-7ae9-4aed-be5c-21875c1999a1)](https://codebeat.co/projects/github-com-securecamera-securecameraios-main)

# Build Info

Run periphery:

```
periphery scan --format xcode --strict --project SnapSafe/SnapSafe.xcodeproj --schemes SnapSafe
```

Resolve package graph:

```
xcodebuild -list
```

# Recommended iOS Settings

Apple provides a number of security features we can use on our devices to ensure the device is as secure as possible. This section outlines settings you can use to protect your device.
Expand Down
195 changes: 130 additions & 65 deletions SnapSafe.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions SnapSafe.xcodeproj/xcshareddata/xcschemes/SnapSafe.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
enableAddressSanitizer = "YES"
enableASanStackUseAfterReturn = "YES"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
<dict>
<key>SchemeUserState</key>
<dict>
<key>Periphery.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>SnapSafe.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
Expand Down
8 changes: 7 additions & 1 deletion SnapSafe.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
}
],
"defaultOptions" : {
"addressSanitizer" : {
"detectStackUseAfterReturn" : true,
"enabled" : true
},
"targetForVariableExpansion" : {
"containerPath" : "container:SnapSafe.xcodeproj",
"identifier" : "A9DE37462DC5F34400679C2C",
"name" : "SnapSafe"
},
"testExecutionOrdering" : "random"
"testExecutionOrdering" : "random",
"testRepetitionMode" : "retryOnFailure",
"undefinedBehaviorSanitizerEnabled" : true
},
"testTargets" : [
{
Expand Down
47 changes: 23 additions & 24 deletions SnapSafe/AppStateCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,86 +5,85 @@
// Created by Bill Booth on 5/22/25.
//

import SwiftUI
import Combine
import SwiftUI

/// Coordinator to manage app state transitions and handle authentication
class AppStateCoordinator: ObservableObject {
// Singleton instance
static let shared = AppStateCoordinator()

// Published properties
@Published var needsAuthentication = false
@Published var wasInBackground = false
@Published var dismissAllSheets = false

// Reference to PIN Manager
private let pinManager = PINManager.shared

// Subscriptions to manage cleanup
private var cancellables = Set<AnyCancellable>()

private init() {
// Listen for scene phase notifications via NotificationCenter as a backup mechanism
// This ensures we catch transitions even in modal sheets
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
.sink { [weak self] _ in
.sink { [weak self] _ in
self?.handleDidEnterBackground()
}
.store(in: &cancellables)

NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
.sink { [weak self] _ in
self?.handleWillEnterForeground()
}
.store(in: &cancellables)

print("AppStateCoordinator initialized")
}
/// Handle when app enters background

// Handle when app enters background
func handleDidEnterBackground() {
print("App entered background")
wasInBackground = true
}
/// Handle when app will enter foreground

// Handle when app will enter foreground
func handleWillEnterForeground() {
print("App will enter foreground, wasInBackground: \(wasInBackground)")
if wasInBackground && pinManager.isPINSet && pinManager.requirePINOnResume {
if wasInBackground, pinManager.isPINSet, pinManager.requirePINOnResume {
// Need to dismiss any open sheets and show authentication
print("Requiring authentication after background")
dismissAllSheets = true

// Slight delay to ensure sheets are dismissed first
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.needsAuthentication = true
}
}

// Update last active time
pinManager.updateLastActiveTime()
}
/// Reset authentication state

// Reset authentication state
func resetAuthenticationState() {
needsAuthentication = false
wasInBackground = false
dismissAllSheets = false
}
/// Signal that authentication is complete

// Signal that authentication is complete
func authenticationComplete() {
needsAuthentication = false
wasInBackground = false
}
}

/// ViewModifier to handle app state transitions
// ViewModifier to handle app state transitions
struct AppStateHandler: ViewModifier {
@ObservedObject private var coordinator = AppStateCoordinator.shared
@Binding var isPresented: Bool

func body(content: Content) -> some View {
content
.onChange(of: coordinator.dismissAllSheets) { _, shouldDismiss in
Expand All @@ -97,8 +96,8 @@ struct AppStateHandler: ViewModifier {
}

extension View {
/// Apply app state handling to modal sheets
// Apply app state handling to modal sheets
func handleAppState(isPresented: Binding<Bool>) -> some View {
modifier(AppStateHandler(isPresented: isPresented))
}
}
}
200 changes: 0 additions & 200 deletions SnapSafe/CamControl.swift

This file was deleted.

Loading
Loading