Skip to content

Commit

Permalink
Basic FIDO reset functionality implemented for NFC keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
jensutbult committed Aug 30, 2024
1 parent 10d974c commit 840d544
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Authenticator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@
B4BB02E02C80BEBD00B72904 /* OATHSavedPasswordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4BB02DF2C80BEBD00B72904 /* OATHSavedPasswordsView.swift */; };
B4BB02E22C81A82300B72904 /* FIDOPINViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4BB02E12C81A82300B72904 /* FIDOPINViewModel.swift */; };
B4BB02E42C81B21D00B72904 /* FIDOPINView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4BB02E32C81B21D00B72904 /* FIDOPINView.swift */; };
B4BB02E62C81C75E00B72904 /* FIDOResetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4BB02E52C81C75D00B72904 /* FIDOResetViewModel.swift */; };
B4BB02E82C81C7A700B72904 /* FIDOResetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4BB02E72C81C7A700B72904 /* FIDOResetView.swift */; };
B4C93E60299D156C00C2A8B8 /* ErrorAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C93E5F299D156C00C2A8B8 /* ErrorAlertView.swift */; };
B4C93E63299FB51A00C2A8B8 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C93E62299FB51A00C2A8B8 /* Account.swift */; };
B4C93E65299FC67800C2A8B8 /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C93E64299FC67800C2A8B8 /* View+Extensions.swift */; };
Expand Down Expand Up @@ -271,6 +273,8 @@
B4BB02DF2C80BEBD00B72904 /* OATHSavedPasswordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OATHSavedPasswordsView.swift; sourceTree = "<group>"; };
B4BB02E12C81A82300B72904 /* FIDOPINViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIDOPINViewModel.swift; sourceTree = "<group>"; };
B4BB02E32C81B21D00B72904 /* FIDOPINView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIDOPINView.swift; sourceTree = "<group>"; };
B4BB02E52C81C75D00B72904 /* FIDOResetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIDOResetViewModel.swift; sourceTree = "<group>"; };
B4BB02E72C81C7A700B72904 /* FIDOResetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIDOResetView.swift; sourceTree = "<group>"; };
B4C93E5F299D156C00C2A8B8 /* ErrorAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorAlertView.swift; sourceTree = "<group>"; };
B4C93E62299FB51A00C2A8B8 /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; };
B4C93E64299FC67800C2A8B8 /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -337,6 +341,7 @@
B4BB02DF2C80BEBD00B72904 /* OATHSavedPasswordsView.swift */,
B44E5E802C74BE67007ABB79 /* OATHResetView.swift */,
B4BB02E32C81B21D00B72904 /* FIDOPINView.swift */,
B4BB02E72C81C7A700B72904 /* FIDOResetView.swift */,
);
path = YubiKeyConfiguration;
sourceTree = "<group>";
Expand Down Expand Up @@ -548,6 +553,7 @@
B44E5EB22C777F22007ABB79 /* OATHPasswordViewModel.swift */,
B4BB02DD2C80BC8500B72904 /* OATHSavedPasswordsViewModel.swift */,
B4BB02E12C81A82300B72904 /* FIDOPINViewModel.swift */,
B4BB02E52C81C75D00B72904 /* FIDOResetViewModel.swift */,
);
path = Model;
sourceTree = "<group>";
Expand Down Expand Up @@ -791,6 +797,7 @@
513F34DC246B144300FCE030 /* UIViewAdditions.swift in Sources */,
A5E9DEB0237DE1660011FBF4 /* SettingsConfig.swift in Sources */,
B4719B2C29914051006CDAEA /* AccountRowView.swift in Sources */,
B4BB02E82C81C7A700B72904 /* FIDOResetView.swift in Sources */,
B40327742847AB5000DF4DB0 /* LicensingViewController.swift in Sources */,
B4DB228A299BC373003110ED /* OATHSession.swift in Sources */,
811CD95722FB276A00E2BCBB /* HelpViewController.swift in Sources */,
Expand Down Expand Up @@ -832,6 +839,7 @@
81C4E43D22F94B7B003AFBB8 /* KeySessionError.swift in Sources */,
A544948E23CE546B003E1E07 /* TutorialViewController.swift in Sources */,
51F8E3BD263847BD0010686B /* ManagementViewModel.swift in Sources */,
B4BB02E62C81C75E00B72904 /* FIDOResetViewModel.swift in Sources */,
51EEC532246D34ED00061A8F /* YKFKeyVersion+Extensions.swift in Sources */,
B4BB02E22C81A82300B72904 /* FIDOPINViewModel.swift in Sources */,
B4719B1B298AB641006CDAEA /* MainViewModel.swift in Sources */,
Expand Down
18 changes: 18 additions & 0 deletions Authenticator/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@
}
}
}
},
"Confirm FIDO reset" : {

},
"Confirm OATH reset" : {

Expand Down Expand Up @@ -880,6 +883,12 @@
}
}
}
},
"FIDO accounts deleted and FIDO application reset to factory defaults." : {
"comment" : "FIDO reset confirmation message"
},
"FIDO has been reset" : {

},
"FIDO PIN" : {

Expand Down Expand Up @@ -1799,6 +1808,9 @@
},
"Reset all accounts stored on YubiKey, make sure they are not in use anywhere before doing this." : {

},
"Reset all FIDO accounts stored on YubiKey, make sure they are not in use anywhere before doing this." : {

},
"Reset complete" : {
"comment" : "Reset YubiKey complete alert title",
Expand All @@ -1817,6 +1829,12 @@
}
}
}
},
"Reset FIDO" : {

},
"Reset FIDO application" : {

},
"Reset OATH" : {

Expand Down
55 changes: 55 additions & 0 deletions Authenticator/Model/FIDOResetViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2022 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation

class FIDOResetViewModel: ObservableObject {

@Published var state: ResetState = .ready

enum ResetState: Equatable {
case ready, success, error(String)
}

private let connection = Connection()

func reset() {
connection.startConnection { connection in
connection.fido2Session { session, error in
guard let session = session else {
let errorMessage = error?.localizedDescription ?? "Unknown error"
YubiKitManager.shared.stopNFCConnection(withErrorMessage: errorMessage)
self.state = .error(errorMessage)
return
}
session.reset { error in
if let error = error {
YubiKitManager.shared.stopNFCConnection(withErrorMessage: error.localizedDescription)
self.state = .error(error.localizedDescription)
} else {
let message = String(localized: "FIDO accounts deleted and FIDO application reset to factory defaults.", comment: "FIDO reset confirmation message")
YubiKitManager.shared.stopNFCConnection(withMessage: message)
self.state = .success
}
}
}
}
}

deinit {
print("deinit FIDOResetViewModel")
}
}
16 changes: 15 additions & 1 deletion Authenticator/UI/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,9 @@ All rights reserved.</string>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="vra-Ob-Qva" kind="show" destinationCreationSelector="showFIDOResetView:" id="Rze-2h-Rhl"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
Expand Down Expand Up @@ -1390,13 +1393,24 @@ All rights reserved.</string>
<scene sceneID="q35-YB-QmV">
<objects>
<hostingController id="81V-0g-Iny" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="f8N-jP-3Yg"/>
<navigationItem key="navigationItem" largeTitleDisplayMode="never" id="f8N-jP-3Yg"/>
<nil key="simulatedTopBarMetrics"/>
</hostingController>
<placeholder placeholderIdentifier="IBFirstResponder" id="yIC-xi-Py4" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2265" y="-1154"/>
</scene>
<!--Hosting Controller-->
<scene sceneID="7ni-Tg-erZ">
<objects>
<hostingController id="vra-Ob-Qva" sceneMemberID="viewController">
<navigationItem key="navigationItem" largeTitleDisplayMode="never" id="K8E-BA-kCe"/>
<nil key="simulatedTopBarMetrics"/>
</hostingController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ztG-N1-Yl3" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2938" y="-1155"/>
</scene>
</scenes>
<color key="tintColor" name="YubiBlue"/>
<resources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ extension ConfigurationController {
controller?.title = "FIDO PIN"
return controller
}

@IBSegueAction func showFIDOResetView(_ coder: NSCoder) -> UIViewController? {
let controller = UIHostingController(coder: coder, rootView: FIDOResetView())
controller?.title = "Reset FIDO"
return controller
}
}

extension YKFManagementDeviceInfo {
Expand Down
68 changes: 68 additions & 0 deletions Authenticator/UI/YubiKeyConfiguration/FIDOResetView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2022 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import SwiftUI

struct FIDOResetView: View {

@StateObject var model = FIDOResetViewModel()
@State var presentConfirmAlert = false
@State var presentErrorAlert = false
@State var keyHasBeenReset = false
@State var errorMessage: String? = nil

var body: some View {
SettingsView(image: Image(systemName: "exclamationmark.triangle").foregroundColor(.red)) {
Text(keyHasBeenReset ? "FIDO has been reset" : "Reset FIDO application").font(.headline)
Text("Reset all FIDO accounts stored on YubiKey, make sure they are not in use anywhere before doing this.")
.multilineTextAlignment(.center)
.opacity(keyHasBeenReset ? 0.2 : 1.0)
} buttons: {
SettingsButton("Reset Yubikey") {
presentConfirmAlert.toggle()
}
.disabled(keyHasBeenReset)
}
.navigationBarTitle(Text("Reset FIDO"), displayMode: .inline)
.alert("Confirm FIDO reset", isPresented: $presentConfirmAlert, presenting: model, actions: { model in
Button(role: .destructive) {
presentConfirmAlert.toggle()
model.reset()
} label: {
Text("Reset")
}
Button(role: .cancel) {
presentConfirmAlert.toggle()
} label: {
Text("Cancel")
}
})
.alert(errorMessage ?? "Unknown error", isPresented: $presentErrorAlert, actions: { })
.onChange(of: model.state) { state in
withAnimation {
switch state {
case .ready:
self.keyHasBeenReset = false
case .success:
self.keyHasBeenReset = true
case .error(let message):
self.presentErrorAlert = true
self.errorMessage = message
}
}
}
}
}

0 comments on commit 840d544

Please sign in to comment.