Sesame-iOS/Sesame/ContentView.swift
2022-01-29 18:59:42 +01:00

165 lines
5.2 KiB
Swift

import SwiftUI
import CryptoKit
let keyManager = try! KeyManagement()
let server = Client(server: URL(string: "https://christophhagen.de/sesame/")!)
struct ContentView: View {
@State var state: ClientState = .initial
var canShareKey = false
@State var showNewKeyWarning = false
@State var showKeyGenerationFailedWarning = false
@State var showShareSheetForNewKeys = false
@State var activeRequestCount = 0
var isPerformingRequests: Bool {
activeRequestCount > 0
}
var keyText: String {
let totalKeys = keyManager.numberOfKeys
guard totalKeys > 0 else {
return "No keys available"
}
let unusedKeys = keyManager.unusedKeyCount
guard unusedKeys > 0 else {
return "All keys used"
}
return "\(totalKeys - unusedKeys) / \(totalKeys) keys used"
}
private let buttonWidth: CGFloat = 200
private let topButtonHeight: CGFloat = 60
var body: some View {
VStack(spacing: 20) {
Text(keyText)
Button("Generate new keys", action: {
showNewKeyWarning = true
print("Key regeneration requested")
})
.padding()
.frame(width: buttonWidth, height: topButtonHeight)
.background(.blue)
.foregroundColor(.white)
.cornerRadius(topButtonHeight / 2)
Button("Share one-time key", action: shareKey)
.padding()
.frame(width: buttonWidth, height: topButtonHeight)
.background(.mint)
.foregroundColor(.white)
.cornerRadius(topButtonHeight / 2)
.disabled(!canShareKey)
Spacer()
HStack {
if isPerformingRequests {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
Text(state.description)
.padding()
}
Button(state.openButtonText, action: mainButtonPressed)
.frame(width: buttonWidth, height: 80, alignment: .center)
.background(state.openButtonColor)
.cornerRadius(100)
.foregroundColor(.white)
.font(.title2)
.disabled(!state.openActionIsEnabled)
}
.padding(20)
.onAppear {
checkInitialDeviceStatus()
}.alert(isPresented: $showKeyGenerationFailedWarning) {
Alert(title: Text("The keys could not be generated"),
message: Text("All previous keys will be deleted and the lock will be blocked. Are you sure?"),
dismissButton: .default(Text("Okay")))
}.shareSheet(isPresented: $showShareSheetForNewKeys, items: [keyManager.exportFile])
.alert(isPresented: $showNewKeyWarning) {
Alert(title: Text("Generate new keys"),
message: Text("All previous keys will be deleted and the lock will be blocked. Are you sure?"),
primaryButton: .destructive(Text("Generate"), action: regenerateKeys),
secondaryButton: .cancel())
}
}
func mainButtonPressed() {
print("Main button pressed")
if state.canSendKey {
sendKey()
} else {
checkInitialDeviceStatus()
}
}
func sendKey() {
guard let key = keyManager.useNextKey() else {
state = .allKeysUsed
return
}
state = .waitingForResponse
activeRequestCount += 1
print("Sending key \(key.id)")
Task {
let newState = try await server.keyResponse(key: key.key, id: key.id)
activeRequestCount -= 1
state = newState
}
}
func checkInitialDeviceStatus() {
print("Checking device status")
Task {
do {
activeRequestCount += 1
let newState = try await server.deviceStatus()
activeRequestCount -= 1
print("Device status: \(newState)")
switch newState {
case .noKeysAvailable, .allKeysUsed:
return
default:
state = newState
}
} catch {
print("Failed to get device status: \(error)")
state = .statusRequestFailed
}
}
}
func regenerateKeys() {
print("Regenerate keys")
do {
try keyManager.regenerateKeys()
state = .newKeysGenerated
showKeyGenerationFailedWarning = false
showShareSheetForNewKeys = true
checkInitialDeviceStatus()
} catch {
state = .noKeysAvailable
showKeyGenerationFailedWarning = true
showShareSheetForNewKeys = false
}
}
func shareKey() {
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice("iPhone 8")
}
}