Browse Source

Initial NIP05 code

Also add the ability to login with a NIP05 id
profile-edit
William Casarin 2 years ago
parent
commit
7493641896
  1. 2
      damus/ContentView.swift
  2. 161
      damus/Views/LoginView.swift

2
damus/ContentView.swift

@ -9,7 +9,7 @@ import SwiftUI
import Starscream import Starscream
import Kingfisher import Kingfisher
let BOOTSTRAP_RELAYS = [ var BOOTSTRAP_RELAYS = [
"wss://relay.damus.io", "wss://relay.damus.io",
"wss://nostr-relay.wlvs.space", "wss://nostr-relay.wlvs.space",
"wss://nostr.oxtr.dev", "wss://nostr.oxtr.dev",

161
damus/Views/LoginView.swift

@ -11,14 +11,19 @@ enum ParsedKey {
case pub(String) case pub(String)
case priv(String) case priv(String)
case hex(String) case hex(String)
case nip05(String)
var is_pub: Bool { var is_pub: Bool {
if case .pub = self { if case .pub = self {
return true return true
} }
if case .nip05 = self {
return true
}
return false return false
} }
var is_hex: Bool { var is_hex: Bool {
if case .hex = self { if case .hex = self {
return true return true
@ -31,19 +36,68 @@ 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
func get_error(parsed_key: ParsedKey?) -> String? { func get_error(parsed_key: ParsedKey?) -> String? {
if self.error != nil { if self.error != nil {
return self.error return self.error
} }
if !key.isEmpty && parsed_key == nil { if !key.isEmpty && parsed_key == nil {
return "Invalid key" return "Invalid key"
} }
return nil return nil
} }
func process_login(_ key: ParsedKey, is_pubkey: Bool) -> Bool {
switch key {
case .priv(let priv):
save_privkey(privkey: priv)
guard let pk = privkey_to_pubkey(privkey: priv) else {
return false
}
save_pubkey(pubkey: pk)
case .pub(let pub):
clear_saved_privkey()
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
}
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 {
clear_saved_privkey()
save_pubkey(pubkey: hexstr)
} else {
save_privkey(privkey: hexstr)
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()
@ -52,15 +106,15 @@ struct LoginView: View {
.foregroundColor(.white) .foregroundColor(.white)
.font(.title) .font(.title)
.padding() .padding()
Text("Enter your account key to login:") Text("Enter your account key to login:")
.foregroundColor(.white) .foregroundColor(.white)
.padding() .padding()
KeyInput("nsec1...", key: $key) KeyInput("nsec1...", key: $key)
let parsed = parse_key(key) let parsed = parse_key(key)
if parsed?.is_hex ?? false { if parsed?.is_hex ?? false {
Text("This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key.") Text("This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key.")
.font(.subheadline.bold()) .font(.subheadline.bold())
@ -68,19 +122,19 @@ struct LoginView: View {
PubkeySwitch(isOn: $is_pubkey) PubkeySwitch(isOn: $is_pubkey)
.padding() .padding()
} }
if let error = get_error(parsed_key: parsed) { if let error = get_error(parsed_key: parsed) {
Text(error) Text(error)
.foregroundColor(.red) .foregroundColor(.red)
.padding() .padding()
} }
if parsed?.is_pub ?? false { if parsed?.is_pub ?? false {
Text("This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective.") Text("This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective.")
.foregroundColor(.white) .foregroundColor(.white)
.padding() .padding()
} }
if let p = parsed { if let p = parsed {
DamusWhiteButton("Login") { DamusWhiteButton("Login") {
if !process_login(p, is_pubkey: self.is_pubkey) { if !process_login(p, is_pubkey: self.is_pubkey) {
@ -113,10 +167,15 @@ func parse_key(_ thekey: String) -> ParsedKey? {
if key.count > 0 && key.first! == "@" { if key.count > 0 && key.first! == "@" {
key = String(key.dropFirst()) key = String(key.dropFirst())
} }
if hex_decode(key) != nil { if hex_decode(key) != nil {
return .hex(key) return .hex(key)
} }
if (key.contains { $0 == "@" }) {
return .nip05(key)
}
if let bech_key = decode_bech32_key(key) { if let bech_key = decode_bech32_key(key) {
switch bech_key { switch bech_key {
case .pub(let pk): case .pub(let pk):
@ -125,49 +184,65 @@ func parse_key(_ thekey: String) -> ParsedKey? {
return .priv(sec) return .priv(sec)
} }
} }
return nil return nil
} }
func process_login(_ key: ParsedKey, is_pubkey: Bool) -> Bool { struct NIP05Result: Decodable {
switch key { let names: Dictionary<String, String>
case .priv(let priv): let relays: Dictionary<String, [String]>?
save_privkey(privkey: priv) }
guard let pk = privkey_to_pubkey(privkey: priv) else {
return false struct NIP05User {
} let pubkey: String
save_pubkey(pubkey: pk) let relays: [String]
}
case .pub(let pub):
clear_saved_privkey() func get_nip05_pubkey(id: String) async -> NIP05User? {
save_pubkey(pubkey: pub) let parts = id.components(separatedBy: "@")
case .hex(let hexstr): guard parts.count == 2 else {
if is_pubkey { return nil
clear_saved_privkey() }
save_pubkey(pubkey: hexstr)
} else { let user = parts[0]
save_privkey(privkey: hexstr) let host = parts[1]
guard let pk = privkey_to_pubkey(privkey: hexstr) else {
return false guard let url = URL(string: "https://\(host)/.well-known/nostr.json?name=\(user)") else {
} return nil
save_pubkey(pubkey: pk) }
guard let (data, _) = try? await URLSession.shared.data(for: URLRequest(url: url)) else {
return nil
}
guard let json: NIP05Result = decode_data(data) else {
return nil
}
guard let pubkey = json.names[user] else {
return nil
}
var relays: [String] = []
if let rs = json.relays {
if let rs = rs[user] {
relays = rs
} }
} }
notify(.login, ()) return NIP05User(pubkey: pubkey, relays: relays)
return true
} }
struct KeyInput: View { struct KeyInput: View {
let title: String let title: String
let key: Binding<String> let key: Binding<String>
init(_ title: String, key: Binding<String>) { init(_ title: String, key: Binding<String>) {
self.title = title self.title = title
self.key = key self.key = key
} }
var body: some View { var body: some View {
TextField("", text: key) TextField("", text: key)
.placeholder(when: key.wrappedValue.isEmpty) { .placeholder(when: key.wrappedValue.isEmpty) {

Loading…
Cancel
Save