QR.swift (2402B)
1 // 2 // QR.swift 3 // lightninglink 4 // 5 // Created by William Casarin on 2022-03-12. 6 // 7 8 import Foundation 9 10 11 public enum LNScanResult { 12 case lightning(DecodeType) 13 case lnlink(LNLink) 14 case lnurl(URL) 15 } 16 17 18 func handle_qrcode(_ qr: String) -> Either<String, LNScanResult> { 19 let invstr = qr.trimmingCharacters(in: .whitespacesAndNewlines) 20 var lowered = invstr.lowercased() 21 22 if lowered.starts(with: "lightning:") { 23 let index = invstr.index(invstr.startIndex, offsetBy: 10) 24 lowered = String(lowered[index...]) 25 } 26 27 if lowered.starts(with: "lnlink:") { 28 switch parse_auth_qr(invstr) { 29 case .left(let err): 30 return .left(err) 31 case .right(let lnlink): 32 return .right(.lnlink(lnlink)) 33 } 34 } 35 36 if lowered.starts(with: "lnurl") { 37 guard let bech32 = decode_bech32(lowered) else { 38 return .left("Invalid lnurl bech32 encoding") 39 } 40 41 let url = String(decoding: bech32.dat, as: UTF8.self) 42 if let email = parse_email(str: url) { 43 guard let lnurl = make_lnaddress(email: email) else { 44 return .left("Couldn't make lnaddress from email") 45 } 46 return .right(.lnurl(lnurl)) 47 } 48 49 guard let lnurl = URL(string: url.trimmingCharacters(in: .whitespacesAndNewlines)) else { 50 return .left("Couldn't make lnurl from qr") 51 } 52 53 return .right(.lnurl(lnurl)) 54 } 55 56 if let email = parse_email(str: lowered) { 57 guard let lnurl = make_lnaddress(email: email) else { 58 return .left("Couldn't make lnaddress from email") 59 } 60 return .right(.lnurl(lnurl)) 61 } 62 63 guard let parsed = parseInvoiceString(lowered) else { 64 return .left("Failed to parse invoice") 65 } 66 67 return .right(.lightning(parsed)) 68 } 69 70 71 struct Email { 72 let name: String 73 let host: String 74 } 75 76 func parse_email(str: String) -> Email? { 77 let parts = str.split(separator: "@") 78 79 guard parts.count == 2 else { 80 return nil 81 } 82 83 if parts[0].contains(":") { 84 return nil 85 } 86 87 if !parts[1].contains(".") { 88 return nil 89 } 90 91 let name = String(parts[0]) 92 let host = String(parts[1]) 93 94 return Email(name: name, host: host) 95 } 96 97 98 func make_lnaddress(email: Email) -> URL? { 99 return URL(string: "https://\(email.host)/.well-known/lnurlp/\(email.name)") 100 }