upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/nostr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/nostr.cpp')
-rw-r--r--src/nostr.cpp88
1 files changed, 69 insertions, 19 deletions
diff --git a/src/nostr.cpp b/src/nostr.cpp
index 32cea18..e2d839c 100644
--- a/src/nostr.cpp
+++ b/src/nostr.cpp
@@ -132,6 +132,8 @@ vector<string> vBtfMeetingRelays = {
132bool fBtfRelayPinned = false; 132bool fBtfRelayPinned = false;
133string strBtfActiveRelay; 133string strBtfActiveRelay;
134static CCriticalSection cs_activeRelay; 134static CCriticalSection cs_activeRelay;
135static string strBtfOnionEndpoint;
136static CCriticalSection cs_onionEndpoint;
135 137
136// Only the rendezvous we actually registered at (BtfSetActiveRelay, called from 138// Only the rendezvous we actually registered at (BtfSetActiveRelay, called from
137// ThreadBtfAccept once registration succeeds). Empty until then, on purpose: it 139// ThreadBtfAccept once registration succeeds). Empty until then, on purpose: it
@@ -153,6 +155,26 @@ void BtfSetActiveRelay(const string& relay)
153 strBtfActiveRelay = relay; 155 strBtfActiveRelay = relay;
154} 156}
155 157
158bool BtfSetLocalOnionEndpoint(const string& endpoint, string& errOut)
159{
160 string norm;
161 if (!btf::NormalizeOnionEndpoint(endpoint, norm))
162 {
163 errOut = "expected v3 onion endpoint HOST.onion:PORT";
164 return false;
165 }
166 CRITICAL_BLOCK(cs_onionEndpoint)
167 strBtfOnionEndpoint = norm;
168 return true;
169}
170
171string BtfLocalOnionEndpoint()
172{
173 CRITICAL_BLOCK(cs_onionEndpoint)
174 return strBtfOnionEndpoint;
175 return "";
176}
177
156// A relay this node advertises on Nostr for others to discover (/announcerelay). 178// A relay this node advertises on Nostr for others to discover (/announcerelay).
157string strBtfAnnounceRelay; 179string strBtfAnnounceRelay;
158// Relays learned from other operators' Nostr announcements. 180// Relays learned from other operators' Nostr announcements.
@@ -392,10 +414,16 @@ std::string BtfLocalDescriptor()
392 string meeting; 414 string meeting;
393 CRITICAL_BLOCK(cs_activeRelay) 415 CRITICAL_BLOCK(cs_activeRelay)
394 meeting = strBtfActiveRelay; 416 meeting = strBtfActiveRelay;
417 string onion = BtfLocalOnionEndpoint();
395 if (meeting.empty()) 418 if (meeting.empty())
396 return ""; 419 {
420 if (onion.empty())
421 return "";
422 meeting = "rendezvous-pending";
423 }
397 return btf::SignDescriptor(g_nostrKey.ctx, g_nostrKey.seckey, 424 return btf::SignDescriptor(g_nostrKey.ctx, g_nostrKey.seckey,
398 g_nostrKey.EncPubHex(), meeting, (uint64_t)GetTime()); 425 g_nostrKey.EncPubHex(), meeting, (uint64_t)GetTime(),
426 onion);
399} 427}
400 428
401// The shared secp256k1 context, so net.cpp can verify descriptors that arrive 429// The shared secp256k1 context, so net.cpp can verify descriptors that arrive
@@ -854,17 +882,21 @@ static void PublishDescriptor(CWebSocket& ws, CNostrKey& key)
854 // meeting_node is the rendezvous relay this node's hidden service 882 // meeting_node is the rendezvous relay this node's hidden service
855 // (ThreadBtfAccept in net.cpp) is registered at -- where clients dial us. 883 // (ThreadBtfAccept in net.cpp) is registered at -- where clients dial us.
856 string meeting_node = BtfActiveRelay(); 884 string meeting_node = BtfActiveRelay();
885 string onion = BtfLocalOnionEndpoint();
857 if (meeting_node.empty()) 886 if (meeting_node.empty())
858 { 887 {
859 // Not registered anywhere yet. Publishing now would advertise a meeting 888 if (onion.empty())
860 // node we can't be reached at, and peers would waste dials on it. The 889 {
861 // ThreadNostrSeed loop republishes on every pass, so skipping costs 890 // Not registered anywhere yet, and no direct onion endpoint exists.
862 // nothing but the delay until ThreadBtfAccept registers. 891 // Publishing now would advertise a meeting node we can't be reached at.
863 LogPrint("nostr", "Nostr: skipping descriptor publish, no rendezvous registered yet\n"); 892 LogPrint("nostr", "Nostr: skipping descriptor publish, no rendezvous registered yet\n");
864 return; 893 return;
894 }
895 meeting_node = "rendezvous-pending";
865 } 896 }
866 string desc = btf::SignDescriptor(key.ctx, key.seckey, key.EncPubHex(), 897 string desc = btf::SignDescriptor(key.ctx, key.seckey, key.EncPubHex(),
867 meeting_node, (uint64_t)GetTime()); 898 meeting_node, (uint64_t)GetTime(),
899 onion);
868 if (desc.empty()) 900 if (desc.empty())
869 return; 901 return;
870 json tags = json::array({ json::array({ "d", BTF_DESC_DTAG }) }); 902 json tags = json::array({ json::array({ "d", BTF_DESC_DTAG }) });
@@ -1070,7 +1102,8 @@ static void HandlePoolAnnouncement(const json& ev)
1070// this socket for reuse, and only a completed exchange leaves it in a state 1102// this socket for reuse, and only a completed exchange leaves it in a state
1071// the next caller can trust. 1103// the next caller can trust.
1072static bool ResolveDescriptor(CWebSocket& ws, void* ctx, const string& btfAddr, 1104static bool ResolveDescriptor(CWebSocket& ws, void* ctx, const string& btfAddr,
1073 btf::Descriptor& out, bool& fExchangeOk) 1105 btf::Descriptor& out, bool& fExchangeOk,
1106 string* rawOut = NULL)
1074{ 1107{
1075 fExchangeOk = false; 1108 fExchangeOk = false;
1076 unsigned char pk[32]; 1109 unsigned char pk[32];
@@ -1106,7 +1139,11 @@ static bool ResolveDescriptor(CWebSocket& ws, void* ctx, const string& btfAddr,
1106 const json& ev = j[2]; 1139 const json& ev = j[2];
1107 if (!fFound && ev.contains("content") && 1140 if (!fFound && ev.contains("content") &&
1108 btf::VerifyDescriptor(ctx, ev["content"].get<string>(), pk, out)) 1141 btf::VerifyDescriptor(ctx, ev["content"].get<string>(), pk, out))
1142 {
1109 fFound = true; 1143 fFound = true;
1144 if (rawOut)
1145 *rawOut = ev["content"].get<string>();
1146 }
1110 // Deliberately keep reading to EOSE rather than returning here. 1147 // Deliberately keep reading to EOSE rather than returning here.
1111 // Returning early leaves the rest of the relay's answer queued on a 1148 // Returning early leaves the rest of the relay's answer queued on a
1112 // socket that goes straight back into the pool, and the next caller 1149 // socket that goes straight back into the pool, and the next caller
@@ -1126,8 +1163,10 @@ static bool ResolveDescriptor(CWebSocket& ws, void* ctx, const string& btfAddr,
1126// public discovery relays for the owner's self-certified descriptor. Used by 1163// public discovery relays for the owner's self-certified descriptor. Used by
1127// ConnectNodeBtf in net.cpp. 1164// ConnectNodeBtf in net.cpp.
1128bool BtfResolve(const std::string& btfAddr, std::string& meetingHostPort, 1165bool BtfResolve(const std::string& btfAddr, std::string& meetingHostPort,
1129 unsigned char enc_pub[32]) 1166 unsigned char enc_pub[32], std::string* onionHostPort)
1130{ 1167{
1168 if (onionHostPort)
1169 onionHostPort->clear();
1131 if (!EnsureNostrKey()) 1170 if (!EnsureNostrKey())
1132 return false; 1171 return false;
1133 for (int i = 0; i < nNostrRelays && !fShutdown; i++) 1172 for (int i = 0; i < nNostrRelays && !fShutdown; i++)
@@ -1155,10 +1194,15 @@ bool BtfResolve(const std::string& btfAddr, std::string& meetingHostPort,
1155 } 1194 }
1156 lease.fOk = fExchangeOk; 1195 lease.fOk = fExchangeOk;
1157 if (d.meeting_node.empty() || d.meeting_node == "rendezvous-pending") 1196 if (d.meeting_node.empty() || d.meeting_node == "rendezvous-pending")
1158 continue; // descriptor predates the owner's relay config 1197 {
1198 if (!onionHostPort || d.onion.empty())
1199 continue; // caller needs rendezvous, or descriptor has no direct path
1200 }
1159 if (!HexDecode(d.enc, enc_pub, 32)) 1201 if (!HexDecode(d.enc, enc_pub, 32))
1160 continue; 1202 continue;
1161 meetingHostPort = d.meeting_node; 1203 meetingHostPort = d.meeting_node;
1204 if (onionHostPort)
1205 *onionHostPort = d.onion;
1162 return true; 1206 return true;
1163 } 1207 }
1164 CATCH_PRINT_EXCEPTION("BtfResolve") 1208 CATCH_PRINT_EXCEPTION("BtfResolve")
@@ -1247,12 +1291,15 @@ bool BtfResolveMany(const std::vector<std::string>& btfAddrs,
1247 btf::Descriptor d; 1291 btf::Descriptor d;
1248 if (!btf::VerifyDescriptor(g_nostrKey.ctx, ev["content"].get<string>(), pk, d)) 1292 if (!btf::VerifyDescriptor(g_nostrKey.ctx, ev["content"].get<string>(), pk, d))
1249 continue; 1293 continue;
1250 if (d.meeting_node.empty() || d.meeting_node == "rendezvous-pending") 1294 if ((d.meeting_node.empty() || d.meeting_node == "rendezvous-pending") &&
1295 d.onion.empty())
1251 continue; 1296 continue;
1252 BtfResolvedPeer rp; 1297 BtfResolvedPeer rp;
1253 if (!HexDecode(d.enc, rp.enc_pub, 32)) 1298 if (!HexDecode(d.enc, rp.enc_pub, 32))
1254 continue; 1299 continue;
1255 rp.meetingHostPort = d.meeting_node; 1300 rp.meetingHostPort = d.meeting_node;
1301 rp.onionHostPort = d.onion;
1302 rp.descriptor = ev["content"].get<string>();
1256 out[ai->second] = rp; 1303 out[ai->second] = rp;
1257 pending.erase(ai->second); 1304 pending.erase(ai->second);
1258 } 1305 }
@@ -1729,11 +1776,13 @@ static void ConnectDiscoveredBtfPeers()
1729 DialCtx* ctx = (DialCtx*)arg; 1776 DialCtx* ctx = (DialCtx*)arg;
1730 string addr = ctx->addr; 1777 string addr = ctx->addr;
1731 string meeting = ctx->rp.meetingHostPort; 1778 string meeting = ctx->rp.meetingHostPort;
1779 string onion = ctx->rp.onionHostPort;
1780 string desc = ctx->rp.descriptor;
1732 unsigned char enc_pub[32]; 1781 unsigned char enc_pub[32];
1733 memcpy(enc_pub, ctx->rp.enc_pub, 32); 1782 memcpy(enc_pub, ctx->rp.enc_pub, 32);
1734 delete ctx; 1783 delete ctx;
1735 1784
1736 CNode* pnode = ConnectNodeBtfResolved(addr, meeting, enc_pub); 1785 CNode* pnode = ConnectNodeBtfResolved(addr, meeting, onion, enc_pub, desc);
1737 CRITICAL_BLOCK(cs_btfPeerState) 1786 CRITICAL_BLOCK(cs_btfPeerState)
1738 { 1787 {
1739 if (pnode) 1788 if (pnode)
@@ -1795,11 +1844,12 @@ void ThreadNostrSeed(void* parg)
1795 LogPrint("nostr", "Nostr: node pubkey = %s\n", key.PubKeyHex().c_str()); 1844 LogPrint("nostr", "Nostr: node pubkey = %s\n", key.PubKeyHex().c_str());
1796 LogPrint("nostr", "Nostr: node .btf address = %s\n", key.BtfAddress().c_str()); 1845 LogPrint("nostr", "Nostr: node .btf address = %s\n", key.BtfAddress().c_str());
1797 1846
1798 // The self-test below publishes a real descriptor, and PublishDescriptor now 1847 // The self-test below publishes a real descriptor. Rendezvous-only nodes
1799 // refuses to publish before ThreadBtfAccept has registered a rendezvous. Give 1848 // need ThreadBtfAccept to register first; Tor nodes can publish as soon as
1800 // registration a bounded head start so the test measures the publish/resolve 1849 // their signed onion endpoint exists, with rendezvous marked pending.
1801 // chain instead of losing the race against it. 1850 for (int i = 0; i < 60 && !fShutdown &&
1802 for (int i = 0; i < 60 && !fShutdown && BtfActiveRelay().empty(); i++) 1851 BtfActiveRelay().empty() &&
1852 BtfLocalOnionEndpoint().empty(); i++)
1803 Sleep(1000); 1853 Sleep(1000);
1804 1854
1805 // One-time self-test of the rendezvous: publish our descriptor to a relay, 1855 // One-time self-test of the rendezvous: publish our descriptor to a relay,