Save keys when logging in and when creating new keypair
Changelog-Added: Save keys when logging in and when creating new keypair Closes: #1042
This commit is contained in:
committed by
William Casarin
parent
3284832eb0
commit
03931ef70e
@@ -259,6 +259,7 @@
|
|||||||
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
||||||
50088DA129E8271A008A1FDF /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50088DA029E8271A008A1FDF /* WebSocket.swift */; };
|
50088DA129E8271A008A1FDF /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50088DA029E8271A008A1FDF /* WebSocket.swift */; };
|
||||||
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
|
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
|
||||||
|
50B5685329F97CB400A23243 /* CredentialHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B5685229F97CB400A23243 /* CredentialHandler.swift */; };
|
||||||
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */; };
|
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */; };
|
||||||
5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; };
|
5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; };
|
||||||
5C513FCC2984ACA60072348F /* QRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FCB2984ACA60072348F /* QRCodeView.swift */; };
|
5C513FCC2984ACA60072348F /* QRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FCB2984ACA60072348F /* QRCodeView.swift */; };
|
||||||
@@ -681,6 +682,7 @@
|
|||||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
||||||
50088DA029E8271A008A1FDF /* WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocket.swift; sourceTree = "<group>"; };
|
50088DA029E8271A008A1FDF /* WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocket.swift; sourceTree = "<group>"; };
|
||||||
50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; };
|
50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; };
|
||||||
|
50B5685229F97CB400A23243 /* CredentialHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialHandler.swift; sourceTree = "<group>"; };
|
||||||
5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyUserSearchView.swift; sourceTree = "<group>"; };
|
5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyUserSearchView.swift; sourceTree = "<group>"; };
|
||||||
5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = "<group>"; };
|
5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = "<group>"; };
|
||||||
5C513FCB2984ACA60072348F /* QRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeView.swift; sourceTree = "<group>"; };
|
5C513FCB2984ACA60072348F /* QRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeView.swift; sourceTree = "<group>"; };
|
||||||
@@ -1059,6 +1061,7 @@
|
|||||||
4C8D00CB29DF92DF0036AF10 /* Hashtags.swift */,
|
4C8D00CB29DF92DF0036AF10 /* Hashtags.swift */,
|
||||||
4CDA128B29EB19C40006FA5A /* LocalNotification.swift */,
|
4CDA128B29EB19C40006FA5A /* LocalNotification.swift */,
|
||||||
4CA5588229F33F5B00DC6A45 /* StringCodable.swift */,
|
4CA5588229F33F5B00DC6A45 /* StringCodable.swift */,
|
||||||
|
50B5685229F97CB400A23243 /* CredentialHandler.swift */,
|
||||||
);
|
);
|
||||||
path = Util;
|
path = Util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1761,6 +1764,7 @@
|
|||||||
4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */,
|
4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */,
|
||||||
4C5F9118283D88E40052CD1C /* FollowingModel.swift in Sources */,
|
4C5F9118283D88E40052CD1C /* FollowingModel.swift in Sources */,
|
||||||
4C1A9A1A29DCA17E00516EAC /* ReplyCounter.swift in Sources */,
|
4C1A9A1A29DCA17E00516EAC /* ReplyCounter.swift in Sources */,
|
||||||
|
50B5685329F97CB400A23243 /* CredentialHandler.swift in Sources */,
|
||||||
643EA5C8296B764E005081BB /* RelayFilterView.swift in Sources */,
|
643EA5C8296B764E005081BB /* RelayFilterView.swift in Sources */,
|
||||||
4C3EA67D28FFBBA300C48A62 /* InvoicesView.swift in Sources */,
|
4C3EA67D28FFBBA300C48A62 /* InvoicesView.swift in Sources */,
|
||||||
4C363A8E28236FE4006E126D /* NoteContentView.swift in Sources */,
|
4C363A8E28236FE4006E126D /* NoteContentView.swift in Sources */,
|
||||||
|
|||||||
48
damus/Util/CredentialHandler.swift
Normal file
48
damus/Util/CredentialHandler.swift
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// CredentialHandler.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Bryan Montz on 4/26/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import AuthenticationServices
|
||||||
|
|
||||||
|
final class CredentialHandler: NSObject, ASAuthorizationControllerDelegate {
|
||||||
|
|
||||||
|
func check_credentials() {
|
||||||
|
let requests: [ASAuthorizationRequest] = [ASAuthorizationPasswordProvider().createRequest()]
|
||||||
|
let authorizationController = ASAuthorizationController(authorizationRequests: requests)
|
||||||
|
authorizationController.delegate = self
|
||||||
|
authorizationController.performRequests()
|
||||||
|
}
|
||||||
|
|
||||||
|
func save_credential(pubkey: String, privkey: String) {
|
||||||
|
SecAddSharedWebCredential("damus.io" as CFString, pubkey as CFString, privkey as CFString, { error in
|
||||||
|
if let error {
|
||||||
|
print("⚠️ An error occurred while saving credentials: \(error)")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - ASAuthorizationControllerDelegate
|
||||||
|
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
|
||||||
|
guard let cred = authorization.credential as? ASPasswordCredential,
|
||||||
|
let parsedKey = parse_key(cred.password) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Task {
|
||||||
|
switch parsedKey {
|
||||||
|
case .pub, .priv:
|
||||||
|
try? await process_login(parsedKey, is_pubkey: false)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
||||||
|
print("⚠️ Warning: authentication failed with error: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ struct LoginView: View {
|
|||||||
@State var key: String = ""
|
@State var key: String = ""
|
||||||
@State var is_pubkey: Bool = false
|
@State var is_pubkey: Bool = false
|
||||||
@State var error: String? = nil
|
@State var error: String? = nil
|
||||||
|
@State private var credential_handler = CredentialHandler()
|
||||||
|
|
||||||
func get_error(parsed_key: ParsedKey?) -> String? {
|
func get_error(parsed_key: ParsedKey?) -> String? {
|
||||||
if self.error != nil {
|
if self.error != nil {
|
||||||
@@ -43,85 +44,12 @@ struct LoginView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !key.isEmpty && parsed_key == nil {
|
if !key.isEmpty && parsed_key == nil {
|
||||||
return "Invalid key"
|
return LoginError.invalid_key.errorDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func process_login(_ key: ParsedKey, is_pubkey: Bool) -> Bool {
|
|
||||||
switch key {
|
|
||||||
case .priv(let priv):
|
|
||||||
do {
|
|
||||||
try save_privkey(privkey: priv)
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let pk = privkey_to_pubkey(privkey: priv) else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
save_pubkey(pubkey: pk)
|
|
||||||
|
|
||||||
case .pub(let pub):
|
|
||||||
do {
|
|
||||||
try clear_saved_privkey()
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
save_pubkey(pubkey: pub)
|
|
||||||
|
|
||||||
case .nip05(let id):
|
|
||||||
Task.init {
|
|
||||||
guard let nip05 = await get_nip05_pubkey(id: id) else {
|
|
||||||
self.error = "Could not fetch pubkey"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a weird way to login anyways
|
|
||||||
/*
|
|
||||||
var bootstrap_relays = load_bootstrap_relays(pubkey: nip05.pubkey)
|
|
||||||
for relay in nip05.relays {
|
|
||||||
if !(bootstrap_relays.contains { $0 == relay }) {
|
|
||||||
bootstrap_relays.append(relay)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
save_pubkey(pubkey: nip05.pubkey)
|
|
||||||
|
|
||||||
notify(.login, ())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case .hex(let hexstr):
|
|
||||||
if is_pubkey {
|
|
||||||
do {
|
|
||||||
try clear_saved_privkey()
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
save_pubkey(pubkey: hexstr)
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
try save_privkey(privkey: hexstr)
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let pk = privkey_to_pubkey(privkey: hexstr) else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
save_pubkey(pubkey: pk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notify(.login, ())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
DamusGradient()
|
DamusGradient()
|
||||||
@@ -163,14 +91,21 @@ struct LoginView: View {
|
|||||||
|
|
||||||
if let p = parsed {
|
if let p = parsed {
|
||||||
DamusWhiteButton(NSLocalizedString("Login", comment: "Button to log into account.")) {
|
DamusWhiteButton(NSLocalizedString("Login", comment: "Button to log into account.")) {
|
||||||
if !process_login(p, is_pubkey: self.is_pubkey) {
|
Task {
|
||||||
self.error = NSLocalizedString("Invalid key", comment: "Error message indicating that an invalid account key was entered for login.")
|
do {
|
||||||
|
try await process_login(p, is_pubkey: is_pubkey)
|
||||||
|
} catch {
|
||||||
|
self.error = error.localizedDescription
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
.onAppear {
|
||||||
|
credential_handler.check_credentials()
|
||||||
|
}
|
||||||
.navigationBarBackButtonHidden(true)
|
.navigationBarBackButtonHidden(true)
|
||||||
.navigationBarItems(leading: BackNav())
|
.navigationBarItems(leading: BackNav())
|
||||||
}
|
}
|
||||||
@@ -214,6 +149,71 @@ func parse_key(_ thekey: String) -> ParsedKey? {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum LoginError: LocalizedError {
|
||||||
|
case invalid_key
|
||||||
|
case nip05_failed
|
||||||
|
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .invalid_key:
|
||||||
|
return NSLocalizedString("Invalid key", comment: "Error message indicating that an invalid account key was entered for login.")
|
||||||
|
case .nip05_failed:
|
||||||
|
return "Could not fetch pubkey"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func process_login(_ key: ParsedKey, is_pubkey: Bool) async throws {
|
||||||
|
switch key {
|
||||||
|
case .priv(let priv):
|
||||||
|
try handle_privkey(priv)
|
||||||
|
case .pub(let pub):
|
||||||
|
try clear_saved_privkey()
|
||||||
|
save_pubkey(pubkey: pub)
|
||||||
|
|
||||||
|
case .nip05(let id):
|
||||||
|
guard let nip05 = await get_nip05_pubkey(id: id) else {
|
||||||
|
throw LoginError.nip05_failed
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a weird way to login anyways
|
||||||
|
/*
|
||||||
|
var bootstrap_relays = load_bootstrap_relays(pubkey: nip05.pubkey)
|
||||||
|
for relay in nip05.relays {
|
||||||
|
if !(bootstrap_relays.contains { $0 == relay }) {
|
||||||
|
bootstrap_relays.append(relay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
save_pubkey(pubkey: nip05.pubkey)
|
||||||
|
|
||||||
|
case .hex(let hexstr):
|
||||||
|
if is_pubkey {
|
||||||
|
try clear_saved_privkey()
|
||||||
|
save_pubkey(pubkey: hexstr)
|
||||||
|
} else {
|
||||||
|
try handle_privkey(hexstr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_privkey(_ privkey: String) throws {
|
||||||
|
try save_privkey(privkey: privkey)
|
||||||
|
|
||||||
|
guard let pk = privkey_to_pubkey(privkey: privkey) else {
|
||||||
|
throw LoginError.invalid_key
|
||||||
|
}
|
||||||
|
|
||||||
|
if let pub = bech32_pubkey(pk), let priv = bech32_privkey(privkey) {
|
||||||
|
CredentialHandler().save_credential(pubkey: pub, privkey: priv)
|
||||||
|
}
|
||||||
|
save_pubkey(pubkey: pk)
|
||||||
|
}
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
notify(.login, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct NIP05Result: Decodable {
|
struct NIP05Result: Decodable {
|
||||||
let names: Dictionary<String, String>
|
let names: Dictionary<String, String>
|
||||||
let relays: Dictionary<String, [String]>?
|
let relays: Dictionary<String, [String]>?
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Security
|
||||||
|
|
||||||
struct SaveKeysView: View {
|
struct SaveKeysView: View {
|
||||||
let account: CreateAccountModel
|
let account: CreateAccountModel
|
||||||
@@ -16,6 +17,8 @@ struct SaveKeysView: View {
|
|||||||
@State var loading: Bool = false
|
@State var loading: Bool = false
|
||||||
@State var error: String? = nil
|
@State var error: String? = nil
|
||||||
|
|
||||||
|
@State private var credential_handler = CredentialHandler()
|
||||||
|
|
||||||
@FocusState var pubkey_focused: Bool
|
@FocusState var pubkey_focused: Bool
|
||||||
@FocusState var privkey_focused: Bool
|
@FocusState var privkey_focused: Bool
|
||||||
|
|
||||||
@@ -97,6 +100,8 @@ struct SaveKeysView: View {
|
|||||||
|
|
||||||
self.pool.register_handler(sub_id: "signup", handler: handle_event)
|
self.pool.register_handler(sub_id: "signup", handler: handle_event)
|
||||||
|
|
||||||
|
credential_handler.save_credential(pubkey: account.pubkey_bech32, privkey: account.privkey_bech32)
|
||||||
|
|
||||||
self.loading = true
|
self.loading = true
|
||||||
|
|
||||||
self.pool.connect()
|
self.pool.connect()
|
||||||
|
|||||||
Reference in New Issue
Block a user