Skip to content

Commit

Permalink
feat(encryption): polish key transfer flow
Browse files Browse the repository at this point in the history
  • Loading branch information
mhamann committed Aug 24, 2022
1 parent 2974a42 commit 5740a01
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 32 deletions.
4 changes: 4 additions & 0 deletions RowndFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
B35E1ED12874C9C9007E989F /* HubViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B35E1ED02874C9C9007E989F /* HubViewController.swift */; };
B35E1ED32874DBEC007E989F /* SpinnerViewController.swift.bak in Sources */ = {isa = PBXBuildFile; fileRef = B35E1ED22874DBEC007E989F /* SpinnerViewController.swift.bak */; };
B36D430D28B4077F0038CF16 /* MagicLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = B36D430C28B4077F0038CF16 /* MagicLink.swift */; };
B36D430F28B5CCD20038CF16 /* KeyTransferProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B36D430E28B5CCD20038CF16 /* KeyTransferProgress.swift */; };
B374E55C28545A1C00955719 /* framework.h in Headers */ = {isa = PBXBuildFile; fileRef = B374E55B28545A1C00955719 /* framework.h */; settings = {ATTRIBUTES = (Public, ); }; };
B374E5662855873100955719 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = B374E5652855872F00955719 /* Color.swift */; };
B38A4085287E16EE00FD0813 /* LoggingExcluded.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38A4084287E16EE00FD0813 /* LoggingExcluded.swift */; };
Expand Down Expand Up @@ -100,6 +101,7 @@
B35E1ED02874C9C9007E989F /* HubViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HubViewController.swift; sourceTree = "<group>"; };
B35E1ED22874DBEC007E989F /* SpinnerViewController.swift.bak */ = {isa = PBXFileReference; lastKnownFileType = text; path = SpinnerViewController.swift.bak; sourceTree = "<group>"; };
B36D430C28B4077F0038CF16 /* MagicLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicLink.swift; sourceTree = "<group>"; };
B36D430E28B5CCD20038CF16 /* KeyTransferProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyTransferProgress.swift; sourceTree = "<group>"; };
B374E55828545A1C00955719 /* Rownd.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Rownd.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B374E55B28545A1C00955719 /* framework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = framework.h; sourceTree = "<group>"; };
B374E5652855872F00955719 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -335,6 +337,7 @@
B3F01B0428A8A66700EE764B /* KeyTransferView.swift */,
B3F01B1128ABE9C400EE764B /* KeyScanner.swift */,
B3F01B1E28AC9AF300EE764B /* KeyCodeView.swift */,
B36D430E28B5CCD20038CF16 /* KeyTransferProgress.swift */,
);
path = KeyTransfer;
sourceTree = "<group>";
Expand Down Expand Up @@ -529,6 +532,7 @@
B36D430D28B4077F0038CF16 /* MagicLink.swift in Sources */,
B302E2C928650C1D005FD927 /* APIClient.swift in Sources */,
B302E2862863A8D0005FD927 /* HubWebViewController.swift in Sources */,
B36D430F28B5CCD20038CF16 /* KeyTransferProgress.swift in Sources */,
B347C24F2877DAB600935115 /* Encryption.swift in Sources */,
B38A4097287FC7BB00FD0813 /* AccountManagerViewController.swift in Sources */,
B38A40E02887410300FD0813 /* AppleSignUpCoordinator.swift in Sources */,
Expand Down
11 changes: 8 additions & 3 deletions Sources/Rownd/Rownd.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class Rownd: NSObject {
}
}

if !inst.state().state.auth.isAuthenticated {
if !store.state.auth.isAuthenticated {
var launchUrl: URL?
if let _launchUrl = launchOptions?[.url] as? URL {
launchUrl = _launchUrl
Expand All @@ -51,7 +51,6 @@ public class Rownd: NSObject {
if (launchUrl?.host?.hasSuffix("rownd.link")) != nil, let launchUrl = launchUrl {
logger.trace("launch_url: \(String(describing: launchUrl.absoluteString))")

// TODO: Ask Rownd to handle this link (probably signing the user in)
do {
try await SignInLinks.signInWithLink(launchUrl)
} catch {
Expand Down Expand Up @@ -99,7 +98,13 @@ public class Rownd: NSObject {
}

public static func manageUser() {
inst.displayViewControllerOnTop(AccountManagerViewController())
var behavior: LBBottomSheet.BottomSheetController.Behavior = .init(swipeMode: .full)
behavior.heightMode = .specific(values: [.screenRatio(value: 1), .screenRatio(value: 0.65)], heightLimit: .statusBar)

var theme: LBBottomSheet.BottomSheetController.Theme = .init()
theme.grabber?.topMargin = CGFloat(10.0)

inst.getRootViewController()?.presentAsBottomSheet(AccountManagerViewController(), theme: theme, behavior: behavior)
}

public static func getAccessToken() async -> String? {
Expand Down
18 changes: 15 additions & 3 deletions Sources/Rownd/Views/KeyTransfer/KeyScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@ import SwiftUI
import CodeScanner

struct KeyScannerView: View {
@State private var isPresentingScanner = false
var receiveKeyTransfer: (_ url: String) -> Void
@State private var isPresentingScanner = true
@State private var scannedCode: String?
@State private var isTransferringKey = false
@State private var activeNavSelection = ""

var body: some View {
ZStack {
Color(.systemGray6).edgesIgnoringSafeArea(.all)
VStack(alignment: .leading, spacing: 10) {
if let code = scannedCode {

// let url = URL(string: code)
// if let url = url {
// SignInLinks.signInWithLink(url)
// }
// NavigationLink("Next page", destination: NextView(scannedCode: code), isActive: .constant(true)).hidden()
}

Expand All @@ -30,8 +38,10 @@ struct KeyScannerView: View {
CodeScannerView(codeTypes: [.qr]) { response in
if case let .success(result) = response {
scannedCode = result.string
isPresentingScanner = false
// isPresentingScanner = false
isTransferringKey = true
print(result.string)
receiveKeyTransfer(result.string)
}
}
.cornerRadius(15)
Expand All @@ -41,7 +51,7 @@ struct KeyScannerView: View {
Spacer()

Button(action: {

}, label: {
Text("Enter code manually")
})
Expand All @@ -50,6 +60,8 @@ struct KeyScannerView: View {
Spacer()
}

NavigationLink(destination: KeyTransferProgress(isShowingProgressView: $isTransferringKey), isActive: $isTransferringKey) { EmptyView() }

}
.padding(.horizontal)
}
Expand Down
114 changes: 114 additions & 0 deletions Sources/Rownd/Views/KeyTransfer/KeyTransferProgress.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// KeyTransferProgress.swift
// RowndSDK
//
// Created by Matt Hamann on 8/23/22.
//

import Foundation
import SwiftUI

struct KeyTransferProgress: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var keyState: KeyTransferViewState

@Binding var isShowingProgressView: Bool

var body: some View {
ZStack {
Color(.systemGray6).edgesIgnoringSafeArea(.all)
VStack(alignment: .leading, spacing: 10) {
Text("Hang on just a sec. Don't close this window.")
.font(.subheadline)
Spacer()
if keyState.isReceivingKey {
VStack(alignment: .center, spacing: 20) {
HStack(alignment: .center) {
Spacer()
ProgressView()
.scaleEffect(2)
Spacer()
}

HStack(alignment: .center) {
Spacer()
Text("Securely syncing your data to this device...")
.multilineTextAlignment(.center)
.padding(.horizontal)
.frame(minWidth: 0, maxWidth: .infinity)
Spacer()
}
}.frame(maxHeight: .infinity)

Spacer()

HStack(alignment: .center) {
Spacer()
Button(action: {
presentationMode.wrappedValue.dismiss()
}, label: {
Text("Cancel")
})
Spacer()
}.padding(.bottom)
} else if keyState.operationError != nil {
VStack(alignment: .center, spacing: 20) {
HStack(alignment: .center) {
Spacer()
Image(systemName: "x.circle.fill")
.resizable()
.frame(width: 32, height: 32, alignment: .center)
Spacer()
}

HStack(alignment: .center) {
Spacer()
Text("Something went wrong. Please initiate the transfer again.")
.multilineTextAlignment(.center)
.padding(.horizontal)
.frame(minWidth: 0, maxWidth: .infinity)
Spacer()
}

Button(action: {
isShowingProgressView = false
}, label: {
Text("Try again")
})
}.frame(maxHeight: .infinity)
} else {
VStack(alignment: .center, spacing: 20) {
HStack(alignment: .center) {
Spacer()
Image(systemName: "checkmark.circle.fill")
.resizable()
.frame(width: 32, height: 32, alignment: .center)
Spacer()
}

HStack(alignment: .center) {
Spacer()
Text("Success!")
.multilineTextAlignment(.center)
.padding(.horizontal)
.frame(minWidth: 0, maxWidth: .infinity)
Spacer()
}
}.frame(maxHeight: .infinity)
}
}
.padding(.horizontal)
}
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
VStack(alignment: .leading) {
Text("Signing in with your key")
.font(.headline)
.padding(.top)
}
}
}
}
}

39 changes: 21 additions & 18 deletions Sources/Rownd/Views/KeyTransfer/KeyTransferView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ struct KeyTransferView : View {

var parentViewController: UIViewController?
var setupKeyTransfer: () -> Void
var receiveKeyTransfer: (_ url: String) -> Void

@State var appName = "app_name"
@State private var isShowingCode = false
@State private var activeNavSelection: String? = nil
@State private var isShowingAlert = false
@State private var alertTitle = ""
Expand All @@ -31,26 +31,28 @@ struct KeyTransferView : View {
HStack(alignment: .top) {
VStack(alignment: .leading) {

Text("Your encryption key is already saved to your iCloud keychain. To view your key or transfer it to another device, tap below.")
.fixedSize(horizontal: false, vertical: true)
if store.state.auth.isAuthenticated {
Text("Your encryption key is already saved to your iCloud keychain. To view your key or transfer it to another device, tap below.")
.fixedSize(horizontal: false, vertical: true)

Button(action: {
self.setupKeyTransfer()
activeNavSelection = "key-code"
parentViewController?.bottomSheetController?.grow(toMaximumHeight: true)
}, label: {
Text("Show encrpytion key")
.frame(minWidth: 0, maxWidth: .infinity)
})
.modifier(RowndButton())
Button(action: {
self.setupKeyTransfer()
activeNavSelection = "key-code"
parentViewController?.bottomSheetController?.grow(toMaximumHeight: true)
}, label: {
Text("Show encrpytion key")
.frame(minWidth: 0, maxWidth: .infinity)
})
.modifier(RowndButton())
}

Text("To sign in to your account using another device, scan the encryption key QR code that's displayed on the other device.")
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 50)
Button(action: {
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
isShowingCode = true
activeNavSelection = "key-scanner"
parentViewController?.bottomSheetController?.grow(toMaximumHeight: true)
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
Expand Down Expand Up @@ -86,10 +88,7 @@ struct KeyTransferView : View {
dismissButton: .default(Text("OK"))
)
}
NavigationLink(destination: KeyScannerView(), isActive: $isShowingCode) {
EmptyView()
}
NavigationLink(destination: KeyScannerView(), tag: "key-scanner", selection: $activeNavSelection) { EmptyView() }
NavigationLink(destination: KeyScannerView(receiveKeyTransfer: receiveKeyTransfer), tag: "key-scanner", selection: $activeNavSelection) { EmptyView() }
NavigationLink(destination: KeyCodeView(), tag: "key-code", selection: $activeNavSelection) { EmptyView() }

Spacer()
Expand Down Expand Up @@ -120,7 +119,9 @@ struct KeyTransferView : View {
}
}
}
}.environmentObject(keyState)
}
.navigationViewStyle(.stack)
.environmentObject(keyState)
}
}

Expand All @@ -140,6 +141,8 @@ struct KeyTransferView_Previews: PreviewProvider {
static var previews: some View {
KeyTransferView(setupKeyTransfer: {
return
}, receiveKeyTransfer: { url in
return
}, keyState: KeyTransferViewState())
}
}
28 changes: 27 additions & 1 deletion Sources/Rownd/Views/KeyTransfer/KeyTransferViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ import Get
class KeyTransferViewState : ObservableObject {
@Published var key = "Loading..."
@Published var signInLink: String = ""
@Published var isReceivingKey = false
@Published var operationError: String?

var qrCodeData: String {
do {
return try ["data": "\(self.signInLink)/#\(self.key)"].asJsonString()
return try ["data": "\(self.signInLink)#\(self.key)"].asJsonString()
} catch {
return "Error fetching QR Code data: \(String(describing: error))"
}
Expand All @@ -27,6 +30,7 @@ class KeyTransferViewController : UIViewController {
lazy var contentView: UIHostingController<KeyTransferView> = UIHostingController(rootView: KeyTransferView(
parentViewController: self,
setupKeyTransfer: self.setupKeyTransfer,
receiveKeyTransfer: self.receiveKeyTransfer,
keyState: self.keyState
))
var keyState = KeyTransferViewState()
Expand Down Expand Up @@ -68,4 +72,26 @@ class KeyTransferViewController : UIViewController {
}
}

private func receiveKeyTransfer(_ url: String) {
keyState.isReceivingKey = true

Task {
let url = URL(string: url)

guard let url = url else {
keyState.operationError = "The key received was not valid."
keyState.isReceivingKey = false
return
}

do {
try await SignInLinks.signInWithLink(url)
keyState.isReceivingKey = false
} catch {
keyState.operationError = "Key transfer failed. Please try again."
keyState.isReceivingKey = false
}
}
}

}
Loading

0 comments on commit 5740a01

Please sign in to comment.