174 lines
5.6 KiB
Swift
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: Prerelease ")
|
|
Text("Release date: 2023-06-05")
|
|
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("Coming soon", destination: ComingSoonView())
|
|
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("Coming soon", destination: ComingSoonView())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.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()
|
|
}
|
|
}
|