nip42: add initial relay auth support
Lightning-Invoice: lnbc1pjcpaakpp5gjs4f626hf8w6slx84xz3wwhlf309z503rjutckdxv6wwg5ldavsdqqcqzpgxqrrs0fppqjaxxw43p7em4g59vedv7pzl76kt0qyjfsp5qcp9de7a7t8h6zs5mcssfaqp4exrnkehqtg2hf0ary3z5cjnasvs9qyyssq55523e4h3cazhkv7f8jqf5qp0n8spykls49crsu5t3m636u3yj4qdqjkdl2nxf6jet5t2r2pfrxmm8rjpqjd3ylrzqq89m4gqt5l6ycqf92c7h Closes: https://github.com/damus-io/damus/issues/940 Signed-off-by: Charlie Fish <contact@charlie.fish> Signed-off-by: William Casarin <jb55@jb55.com> Changelog-Added: Add NIP-42 relay auth support
This commit is contained in:
committed by
William Casarin
parent
4c37bfc128
commit
84cfeb1604
180
damusTests/AuthIntegrationTests.swift
Normal file
180
damusTests/AuthIntegrationTests.swift
Normal file
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// AuthIntegrationTests.swift
|
||||
// damusTests
|
||||
//
|
||||
// Created by Charlie Fish on 12/22/23.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import damus
|
||||
|
||||
final class AuthIntegrationTests: XCTestCase {
|
||||
func testAuthIntegrationFilterNostrWine() {
|
||||
// Create relay pool and connect to `wss://filter.nostr.wine`
|
||||
let relay_url = RelayURL("wss://filter.nostr.wine")!
|
||||
var received_messages: [String] = []
|
||||
var sent_messages: [String] = []
|
||||
let keypair: Keypair = generate_new_keypair().to_keypair()
|
||||
let pool = RelayPool(ndb: Ndb.test, keypair: keypair)
|
||||
pool.message_received_function = { obj in
|
||||
let str = obj.0
|
||||
let descriptor = obj.1
|
||||
|
||||
if descriptor.url.id != relay_url.id {
|
||||
XCTFail("The descriptor we recieved the message from should equal the relayURL")
|
||||
}
|
||||
|
||||
received_messages.append(str)
|
||||
}
|
||||
pool.message_sent_function = { obj in
|
||||
let str = obj.0
|
||||
let relay = obj.1
|
||||
|
||||
if relay.descriptor.url.id != relay_url.id {
|
||||
XCTFail("The descriptor we sent the message to should equal the relayURL")
|
||||
}
|
||||
|
||||
sent_messages.append(str)
|
||||
}
|
||||
XCTAssertEqual(pool.relays.count, 0)
|
||||
let relay_descriptor = RelayDescriptor.init(url: relay_url, info: .rw)
|
||||
try! pool.add_relay(relay_descriptor)
|
||||
XCTAssertEqual(pool.relays.count, 1)
|
||||
let connection_expectation = XCTestExpectation(description: "Waiting for connection")
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
||||
if pool.num_connected == 1 {
|
||||
connection_expectation.fulfill()
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
wait(for: [connection_expectation], timeout: 30.0)
|
||||
XCTAssertEqual(pool.num_connected, 1)
|
||||
// Assert that AUTH message has been received
|
||||
XCTAssertTrue(received_messages.count >= 1, "expected recieved_messages to be >= 1")
|
||||
let json_received = try! JSONSerialization.jsonObject(with: received_messages[0].data(using: .utf8)!, options: []) as! [Any]
|
||||
XCTAssertEqual(json_received[0] as! String, "AUTH")
|
||||
// Assert that we've replied with the AUTH response
|
||||
XCTAssertEqual(sent_messages.count, 1)
|
||||
let json_sent = try! JSONSerialization.jsonObject(with: sent_messages[0].data(using: .utf8)!, options: []) as! [Any]
|
||||
XCTAssertEqual(json_sent[0] as! String, "AUTH")
|
||||
let sent_msg = json_sent[1] as! [String: Any]
|
||||
XCTAssertEqual(sent_msg["kind"] as! Int, 22242)
|
||||
XCTAssertEqual((sent_msg["tags"] as! [[String]]).first { $0[0] == "challenge" }![1], json_received[1] as! String)
|
||||
}
|
||||
|
||||
func testAuthIntegrationRelayDamusIo() {
|
||||
// Create relay pool and connect to `wss://relay.damus.io`
|
||||
let relay_url = RelayURL("wss://relay.damus.io")!
|
||||
var received_messages: [String] = []
|
||||
var sent_messages: [String] = []
|
||||
let keypair: Keypair = generate_new_keypair().to_keypair()
|
||||
let pool = RelayPool(ndb: Ndb.test, keypair: keypair)
|
||||
pool.message_received_function = { obj in
|
||||
let str = obj.0
|
||||
let descriptor = obj.1
|
||||
|
||||
if descriptor.url.id != relay_url.id {
|
||||
XCTFail("The descriptor we recieved the message from should equal the relayURL")
|
||||
}
|
||||
|
||||
received_messages.append(str)
|
||||
}
|
||||
pool.message_sent_function = { obj in
|
||||
let str = obj.0
|
||||
let relay = obj.1
|
||||
|
||||
if relay.descriptor.url.id != relay_url.id {
|
||||
XCTFail("The descriptor we sent the message to should equal the relayURL")
|
||||
}
|
||||
|
||||
sent_messages.append(str)
|
||||
}
|
||||
XCTAssertEqual(pool.relays.count, 0)
|
||||
let relay_descriptor = RelayDescriptor.init(url: relay_url, info: .rw)
|
||||
try! pool.add_relay(relay_descriptor)
|
||||
XCTAssertEqual(pool.relays.count, 1)
|
||||
let connection_expectation = XCTestExpectation(description: "Waiting for connection")
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
||||
if pool.num_connected == 1 {
|
||||
connection_expectation.fulfill()
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
wait(for: [connection_expectation], timeout: 30.0)
|
||||
XCTAssertEqual(pool.num_connected, 1)
|
||||
// Assert that no AUTH messages have been received
|
||||
XCTAssertEqual(received_messages.count, 0)
|
||||
}
|
||||
|
||||
func testAuthIntegrationNostrWine() {
|
||||
// Create relay pool and connect to `wss://nostr.wine`
|
||||
let relay_url = RelayURL("wss://nostr.wine")!
|
||||
var received_messages: [String] = []
|
||||
var sent_messages: [String] = []
|
||||
let keypair: Keypair = generate_new_keypair().to_keypair()
|
||||
let pool = RelayPool(ndb: Ndb.test, keypair: keypair)
|
||||
pool.message_received_function = { obj in
|
||||
let str = obj.0
|
||||
let descriptor = obj.1
|
||||
|
||||
if descriptor.url.id != relay_url.id {
|
||||
XCTFail("The descriptor we recieved the message from should equal the relayURL")
|
||||
}
|
||||
|
||||
received_messages.append(str)
|
||||
}
|
||||
pool.message_sent_function = { obj in
|
||||
let str = obj.0
|
||||
let relay = obj.1
|
||||
|
||||
if relay.descriptor.url.id != relay_url.id {
|
||||
XCTFail("The descriptor we sent the message to should equal the relayURL")
|
||||
}
|
||||
|
||||
sent_messages.append(str)
|
||||
}
|
||||
XCTAssertEqual(pool.relays.count, 0)
|
||||
let relay_descriptor = RelayDescriptor.init(url: relay_url, info: .rw)
|
||||
try! pool.add_relay(relay_descriptor)
|
||||
XCTAssertEqual(pool.relays.count, 1)
|
||||
let connection_expectation = XCTestExpectation(description: "Waiting for connection")
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
||||
if pool.num_connected == 1 {
|
||||
connection_expectation.fulfill()
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
wait(for: [connection_expectation], timeout: 30.0)
|
||||
XCTAssertEqual(pool.num_connected, 1)
|
||||
// Assert that no AUTH messages have been received
|
||||
XCTAssertEqual(received_messages.count, 0)
|
||||
// Generate UUID for subscription_id
|
||||
let uuid = UUID().uuidString
|
||||
// Send `["REQ", subscription_id, {"kinds": [4]}]`
|
||||
let subscribe = NostrSubscribe(filters: [
|
||||
NostrFilter(kinds: [.dm])
|
||||
], sub_id: uuid)
|
||||
pool.send(NostrRequest.subscribe(subscribe))
|
||||
// Wait for AUTH message to have been received & sent
|
||||
let msg_expectation = XCTestExpectation(description: "Waiting for messages")
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
||||
if received_messages.count >= 2 && sent_messages.count >= 2 {
|
||||
msg_expectation.fulfill()
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
wait(for: [msg_expectation], timeout: 30.0)
|
||||
// Assert that AUTH message has been received
|
||||
XCTAssertTrue(received_messages.count >= 1, "expected recieved_messages to be >= 1")
|
||||
let json_received = try! JSONSerialization.jsonObject(with: received_messages[0].data(using: .utf8)!, options: []) as! [Any]
|
||||
XCTAssertEqual(json_received[0] as! String, "AUTH")
|
||||
// Assert that we've replied with the AUTH response
|
||||
XCTAssertEqual(sent_messages.count, 2)
|
||||
let json_sent = try! JSONSerialization.jsonObject(with: sent_messages[1].data(using: .utf8)!, options: []) as! [Any]
|
||||
XCTAssertEqual(json_sent[0] as! String, "AUTH")
|
||||
let sent_msg = json_sent[1] as! [String: Any]
|
||||
XCTAssertEqual(sent_msg["kind"] as! Int, 22242)
|
||||
XCTAssertEqual((sent_msg["tags"] as! [[String]]).first { $0[0] == "challenge" }![1], json_received[1] as! String)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,18 +13,7 @@ func generate_test_damus_state(
|
||||
mock_profile_info: [Pubkey: Profile]?
|
||||
) -> DamusState {
|
||||
// Create a unique temporary directory
|
||||
var tempDir: String!
|
||||
do {
|
||||
let fileManager = FileManager.default
|
||||
let temp = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString)
|
||||
try fileManager.createDirectory(at: temp, withIntermediateDirectories: true, attributes: nil)
|
||||
tempDir = temp.absoluteString
|
||||
} catch {
|
||||
tempDir = "."
|
||||
}
|
||||
|
||||
print("opening \(tempDir!)")
|
||||
let ndb = try! Ndb(path: tempDir)!
|
||||
let ndb = Ndb.test
|
||||
let our_pubkey = test_pubkey
|
||||
let pool = RelayPool(ndb: ndb)
|
||||
let settings = UserSettingsStore()
|
||||
|
||||
@@ -16,7 +16,34 @@ final class RequestTests: XCTestCase {
|
||||
let expectedResult = "[\"CLOSE\",\"64FD064D-EB9E-4771-8255-8D16981B920B\"]"
|
||||
XCTAssertEqual(result, expectedResult)
|
||||
}
|
||||
|
||||
|
||||
func testMakeAuthRequest() {
|
||||
let challenge_string = "8bc847dd-f2f6-4b3a-9c8a-71776ad9b071"
|
||||
let url = RelayURL("wss://example.com")!
|
||||
let relayInfo = RelayInfo(read: true, write: true)
|
||||
let relayDescriptor = RelayDescriptor(url: url, info: relayInfo)
|
||||
let relayConnection = RelayConnection(url: url) { _ in
|
||||
} processEvent: { _ in
|
||||
}
|
||||
|
||||
let relay = Relay(descriptor: relayDescriptor, connection: relayConnection)
|
||||
let event = make_auth_request(keypair: FullKeypair.init(pubkey: Pubkey.empty, privkey: Privkey.empty), challenge_string: challenge_string, relay: relay)!
|
||||
|
||||
let result = make_nostr_auth_event(ev: event)
|
||||
let json = try! JSONSerialization.jsonObject(with: result!.data(using: .utf8)!, options: []) as! [Any]
|
||||
|
||||
XCTAssertEqual(json[0] as! String, "AUTH")
|
||||
let dictionary = json[1] as! [String: Any]
|
||||
XCTAssertEqual(dictionary["content"] as! String, "")
|
||||
XCTAssertEqual(dictionary["kind"] as! Int, 22242)
|
||||
XCTAssertEqual(dictionary["sig"] as! String, String(repeating: "0", count: 128))
|
||||
XCTAssertEqual(dictionary["pubkey"] as! String, String(repeating: "0", count: 64))
|
||||
let tags = dictionary["tags"] as! [[String]]
|
||||
XCTAssertEqual(tags.first { $0[0] == "relay" }![1], "wss://example.com")
|
||||
XCTAssertEqual(tags.first { $0[0] == "challenge" }![1], challenge_string)
|
||||
XCTAssertEqual(dictionary["id"] as! String, String(repeating: "0", count: 64))
|
||||
}
|
||||
|
||||
/* FIXME: these tests depend on order of json fields which is undefined
|
||||
func testMakePushEvent() {
|
||||
let now = Int64(Date().timeIntervalSince1970)
|
||||
|
||||
26
damusTests/Util/NdbExtensions.swift
Normal file
26
damusTests/Util/NdbExtensions.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// NdbExtensions.swift
|
||||
// damusTests
|
||||
//
|
||||
// Created by Charlie Fish on 12/23/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import damus
|
||||
|
||||
extension Ndb {
|
||||
static var test: Ndb {
|
||||
var tempDir: String!
|
||||
do {
|
||||
let fileManager = FileManager.default
|
||||
let temp = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString)
|
||||
try fileManager.createDirectory(at: temp, withIntermediateDirectories: true, attributes: nil)
|
||||
tempDir = temp.absoluteString
|
||||
} catch {
|
||||
tempDir = "."
|
||||
}
|
||||
|
||||
print("opening \(tempDir!)")
|
||||
return Ndb(path: tempDir)!
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user