-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement
password reminder
prompt (#34)
* Added password reminder view * Added settings, timer and haptic feedback
- Loading branch information
1 parent
ad301a0
commit b1ebe5d
Showing
6 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
Chronos.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
{ | ||
"originHash" : "a10ff4a5835952be5d746ae6edf88cae1d0b20500819d37f98f2f742855d195a", | ||
"pins" : [ | ||
{ | ||
"identity" : "alertkit", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/sparrowcode/AlertKit", | ||
"state" : { | ||
"revision" : "3b73be8db5a7e7efaf474c6ed919f5a437d843c9", | ||
"version" : "5.1.9" | ||
} | ||
}, | ||
{ | ||
"identity" : "cloudkitsyncmonitor", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/ggruen/CloudKitSyncMonitor", | ||
"state" : { | ||
"revision" : "d3bca51a84e416a64bd30d65287041a37f0612f3", | ||
"version" : "1.4.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "codescanner", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/twostraws/CodeScanner.git", | ||
"state" : { | ||
"revision" : "34da57fb63b47add20de8a85da58191523ccce57", | ||
"version" : "2.5.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "cryptoswift", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git", | ||
"state" : { | ||
"revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0", | ||
"version" : "1.8.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "efqrcode", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/EFPrefix/EFQRCode", | ||
"state" : { | ||
"revision" : "2991c2f318ad9529d93b2a73a382a3f9c72c64ce", | ||
"version" : "6.2.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "factory", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/hmlongco/Factory", | ||
"state" : { | ||
"revision" : "587995f7d5cc667951d635fbf6b4252324ba0439", | ||
"version" : "2.3.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-crypto", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-crypto.git", | ||
"state" : { | ||
"revision" : "46072478ca365fe48370993833cb22de9b41567f", | ||
"version" : "3.5.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-log", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-log.git", | ||
"state" : { | ||
"revision" : "9cb486020ebf03bfa5b5df985387a14a98744537", | ||
"version" : "1.6.1" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift_qrcodejs", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/ApolloZhu/swift_qrcodejs.git", | ||
"state" : { | ||
"revision" : "374dc7f7b9e76c6aeb393f6a84590c6d387e1ecb", | ||
"version" : "2.2.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "swiftotp", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/lachlanbell/SwiftOTP.git", | ||
"state" : { | ||
"revision" : "9660551ea3df153c3cbacfa34ac3abbec73a8b84", | ||
"version" : "3.0.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "swiftyjson", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/SwiftyJSON/SwiftyJSON.git", | ||
"state" : { | ||
"revision" : "af76cf3ef710b6ca5f8c05f3a31307d44a3c5828", | ||
"version" : "5.0.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "valet", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/square/Valet", | ||
"state" : { | ||
"revision" : "3df8eaa90e1fa0d80830733cdc3c9e098146af3d", | ||
"version" : "4.3.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "ziparchive", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/ZipArchive/ZipArchive", | ||
"state" : { | ||
"revision" : "79d4dc9729096c6ad83dd3cee2b9f354d1b4ab7b", | ||
"version" : "2.5.5" | ||
} | ||
} | ||
], | ||
"version" : 3 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import AlertKit | ||
import Factory | ||
import SwiftData | ||
import SwiftUI | ||
|
||
struct PasswordReminderView: View { | ||
@Environment(\.dismiss) var dismiss | ||
|
||
@State private var verifyPressed: Bool = false | ||
@State private var password: String = "" | ||
@State private var passwordInvalid: Bool = false | ||
|
||
@FocusState private var focusedField: FocusedField? | ||
|
||
@AppStorage(StateEnum.PASSWORD_REMINDER_ENABLED.rawValue) private var statePasswordReminderEnabled: Bool = false | ||
@AppStorage(StateEnum.NEXT_PASSWORD_REMINDER_TIMESTAMP.rawValue) var nextPasswordReminderTimestamp: TimeInterval = 0 | ||
|
||
let cryptoService = Container.shared.cryptoService() | ||
let vaultService = Container.shared.vaultService() | ||
let swiftDataService = Container.shared.swiftDataService() | ||
|
||
var body: some View { | ||
NavigationStack { | ||
VStack { | ||
Image(systemName: "lock.circle.dotted") | ||
.font(.system(size: 44)) | ||
.padding(.bottom, 16) | ||
|
||
Text("This is an occasional prompt to ensure you don’t forget your password.") | ||
.fixedSize(horizontal: false, vertical: true) | ||
.multilineTextAlignment(.center) | ||
|
||
Group { | ||
HStack { | ||
SecureField("Enter your password", text: $password) | ||
.background(Color.clear) | ||
.focused($focusedField, equals: .password) | ||
.disabled(verifyPressed) | ||
.submitLabel(.done) | ||
.onSubmit { | ||
doSubmit() | ||
} | ||
} | ||
} | ||
.frame(height: 48) | ||
.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) | ||
.background(Color(.systemGray6)) | ||
.cornerRadius(8) | ||
.padding(.top, 32) | ||
|
||
if passwordInvalid { | ||
Text("Invalid password. Check your password and try again.") | ||
.multilineTextAlignment(.center) | ||
.foregroundStyle(.red) | ||
.font(.subheadline) | ||
.padding(.top, 4) | ||
} | ||
|
||
Button { | ||
doSubmit() | ||
} label: { | ||
if !verifyPressed { | ||
Text("Verify") | ||
.bold() | ||
.foregroundStyle(Color(red: 0.04, green: 0, blue: 0.11)) | ||
.frame(minWidth: 0, maxWidth: .infinity) | ||
.frame(height: 32) | ||
.disabled(verifyPressed) | ||
} else { | ||
ProgressView() | ||
.tint(Color(red: 0.04, green: 0, blue: 0.11)) | ||
.frame(minWidth: 0, maxWidth: .infinity) | ||
.frame(height: 32) | ||
} | ||
} | ||
.padding(.top, 32) | ||
.buttonStyle(.borderedProminent) | ||
|
||
Button { | ||
dismiss() | ||
} label: { | ||
Text("Skip") | ||
.bold() | ||
.frame(minWidth: 0, maxWidth: .infinity) | ||
.frame(height: 32) | ||
} | ||
.buttonStyle(.borderless) | ||
} | ||
.padding(16) | ||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) | ||
.background(Color(red: 0.04, green: 0, blue: 0.11).ignoresSafeArea()) | ||
.navigationTitle("Password Reminder") | ||
.navigationBarTitleDisplayMode(.inline) | ||
.onAppear { | ||
focusedField = .password | ||
|
||
nextPasswordReminderTimestamp = Date().timeIntervalSince1970 + (2 * 7 * 24 * 60 * 60) | ||
} | ||
} | ||
.presentationDragIndicator(.visible) | ||
} | ||
|
||
func doSubmit() { | ||
verifyPressed = true | ||
|
||
Task { | ||
let context = ModelContext(swiftDataService.getModelContainer()) | ||
let vault = vaultService.getVault(context: context)! | ||
|
||
let passwordVerified = await cryptoService.unwrapMasterKeyWithUserPassword(vault: vault, password: Array(password.utf8)) | ||
|
||
if passwordVerified { | ||
dismiss() | ||
await UINotificationFeedbackGenerator().notificationOccurred(.success) | ||
} else { | ||
passwordInvalid = true | ||
await UINotificationFeedbackGenerator().notificationOccurred(.error) | ||
} | ||
|
||
verifyPressed = false | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters