splits/Splits/DocsView.swift
2022-08-08 17:41:07 -04:00

174 lines
5.6 KiB
Swift

//
// DocsView.swift
// Splits
//
// Created by Isaac Greene on 2022-06-03.
//
import SwiftUI
import LocalAuthentication
import CryptoKit
/// The system username SHA512 hash for the app
let username = "c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec".utf8
/// The system password SHA512 hash associated with ``username``
let password = "3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2".utf8
/// Holds the views and login for the Docs
///
/// Mostly just a long list of sections and calling views
/// - Note: New views are best called in this `struct`
/// and added to their respective categories
struct DocsView: View {
enum Field: Hashable {
case username
case password
}
/// Makes a SHA512 hash of any `String` passed as input
///
/// Specifically, this function is suited towards checking if
/// the username and password provided by the user
/// match the hashes of the correct ``username`` and ``password``
///
/// - Note: The results of this hash are not seen by the user, so they shouldn't even know
/// this is taking place
///
/// - Returns: A `String` of the computed SHA512 hash
func hashSHA512(login: String) -> String {
let loginAsData = Data(login.utf8)
let loginHashHex = SHA512.hash(data: loginAsData)
let loginHash = loginHashHex.compactMap { String(format: "%02x", $0) }.joined()
return String(loginHash)
}
@State private var pass: String = ""
@State private var user: String = ""
@State private var isUnlocked = false
@FocusState private var focusedField: Field?
var body: some View {
NavigationView {
List {
NavigationLink("Help", destination: HelpView())
NavigationLink("Change Log", destination: ChangeLog())
NavigationLink("Software Licenses", destination: LicenseView())
Section(header: Text("Features")) {
NavigationLink("New", destination: NewFeatures())
NavigationLink("In Progress", destination: InProgressFeatures())
NavigationLink("Deprecated", destination: DeprecatedFeatures())
}
Section(header: Text("Known Issues")) {
NavigationLink("Recently Resolved", destination: RecentlyResolved())
NavigationLink("High Priority", destination: HighPriority())
NavigationLink("Medium Priority", destination: MediumPriority())
NavigationLink("Low Priority", destination: LowPriority())
}
Section(header: Text("App Information")) {
Text("Version: 1.0.0")
Text("Release date: 2022-07-19")
Text("Start date: 2022-03-25")
Link("Built with SwiftUI \(Image(systemName: "swift"))", destination: URL(string: "https://developer.apple.com/xcode/swiftui")!)
}
Section(header: Text("Login")) {
if (isUnlocked) {
NavigationLink("Contacts", destination: SecretView())
Button("Log out") {
pass = ""
user = ""
isUnlocked = false
}
} else {
Button("Log in with biometrics") {
authenticate()
}
SecureField("Username", text: $user)
.keyboardType(.alphabet)
.textContentType(.username)
.submitLabel(.next)
.focused($focusedField, equals: .username)
.textContentType(.username)
SecureField("Password", text: $pass)
.keyboardType(.numbersAndPunctuation)
.textContentType(.password)
.submitLabel(.done)
.focused($focusedField, equals: .password)
.textContentType(.password)
if checkPassword() {
NavigationLink("Contacts", destination: SecretView())
}
}
}
}
.navigationTitle("Docs")
}
.onSubmit {
switch focusedField {
case .username:
focusedField = .password
default:
()
}
if checkPassword() {
isUnlocked = true
}
}
}
/// Compares the `user` SecureField and the `pass` SecureField against ``username`` and ``password``
///
/// - Note: come back to this
///
///
/// - Returns: `true` if `user` equals `username` *and* `pass` equals `password`, `false` if one or both checks return false.
func checkPassword() -> Bool {
if (hashSHA512(login: pass) == String(password) && hashSHA512(login: user) == String(username)) {
return true
} else {
return false
}
}
/// Checks wether the user can use biometrics to sign in
/// and (if true) prompts the user to sign with either FaceID or TouchID
/// depending on the device.
///
/// If the prompt was shown, and the user authenticated correctly
/// `isUnlocked` is set to `true`
///
/// - Note: `authenticate()` has to be called to show the sign-in sheet
func authenticate() {
let context = LAContext()
var error: NSError?
// check whether biometric authentication is possible
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
// it's possible, so go ahead and use it
let reason = "We need authentication before we can show you sensitive data"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
// authentication has now completed
if success {
isUnlocked = true
} else {
()
}
}
} else {
()
}
}
// getting this to work came from
// https://www.hackingwithswift.com/books/ios-swiftui/using-touch-id-and-face-id-with-swiftui
// a truly epic website and it's helped me with
// just about all of my code questions
}
struct DocsView_Previews: PreviewProvider {
static var previews: some View {
DocsView()
}
}