mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-19 19:46:50 +00:00
nip-05 related functions
This commit is contained in:
parent
5204cf7a1c
commit
b0e245e127
@ -11,6 +11,7 @@ mod error;
|
|||||||
mod feed;
|
mod feed;
|
||||||
mod fetcher;
|
mod fetcher;
|
||||||
mod globals;
|
mod globals;
|
||||||
|
mod nip05;
|
||||||
mod overlord;
|
mod overlord;
|
||||||
mod people;
|
mod people;
|
||||||
mod process;
|
mod process;
|
||||||
|
160
src/nip05.rs
Normal file
160
src/nip05.rs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
use crate::db::{DbPerson, DbPersonRelay, DbRelay};
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::globals::GLOBALS;
|
||||||
|
use nostr_types::{Nip05, Unixtime, Url};
|
||||||
|
|
||||||
|
// This updates the people map and the database with the result
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn validate_nip05(person: DbPerson) -> Result<(), Error> {
|
||||||
|
let now = Unixtime::now().unwrap();
|
||||||
|
|
||||||
|
// invalid if their nip-05 is not set
|
||||||
|
if person.dns_id.is_none() {
|
||||||
|
GLOBALS
|
||||||
|
.people
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.upsert_nip05_validity(&person.pubkey, person.dns_id, false, now.0 as u64)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split their DNS ID
|
||||||
|
let dns_id = person.dns_id.clone().unwrap();
|
||||||
|
let (user, domain) = match parse_dns_id(&dns_id) {
|
||||||
|
Ok(pair) => pair,
|
||||||
|
Err(_) => {
|
||||||
|
GLOBALS
|
||||||
|
.people
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.upsert_nip05_validity(&person.pubkey, person.dns_id, false, now.0 as u64)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch NIP-05
|
||||||
|
let nip05 = fetch_nip05(&user, &domain).await?;
|
||||||
|
|
||||||
|
// Check if the response matches their public key
|
||||||
|
match nip05.names.get(&user) {
|
||||||
|
Some(pk) => {
|
||||||
|
if pk.as_hex_string() == person.pubkey.0 {
|
||||||
|
// Validated
|
||||||
|
GLOBALS
|
||||||
|
.people
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.upsert_nip05_validity(&person.pubkey, person.dns_id, true, now.0 as u64)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Failed
|
||||||
|
GLOBALS
|
||||||
|
.people
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.upsert_nip05_validity(&person.pubkey, person.dns_id, false, now.0 as u64)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_and_follow_nip05(dns_id: String) -> Result<(), Error> {
|
||||||
|
// Split their DNS ID
|
||||||
|
let (user, domain) = parse_dns_id(&dns_id)?;
|
||||||
|
|
||||||
|
// Fetch NIP-05
|
||||||
|
let nip05 = fetch_nip05(&user, &domain).await?;
|
||||||
|
|
||||||
|
// Get their pubkey
|
||||||
|
let pubkey = match nip05.names.get(&user) {
|
||||||
|
Some(pk) => pk,
|
||||||
|
None => return Err(Error::Nip05KeyNotFound),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save person
|
||||||
|
GLOBALS
|
||||||
|
.people
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.upsert_nip05_validity(
|
||||||
|
&(*pubkey).into(),
|
||||||
|
Some(dns_id.clone()),
|
||||||
|
true,
|
||||||
|
Unixtime::now().unwrap().0 as u64,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Mark as followed
|
||||||
|
GLOBALS
|
||||||
|
.people
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.async_follow(&(*pubkey).into(), true)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
tracing::info!("Followed {}", &dns_id);
|
||||||
|
|
||||||
|
// Set their relays
|
||||||
|
let relays = match nip05.relays.get(pubkey) {
|
||||||
|
Some(relays) => relays,
|
||||||
|
None => return Err(Error::Nip05RelaysNotFound),
|
||||||
|
};
|
||||||
|
for relay in relays.iter() {
|
||||||
|
// Save relay
|
||||||
|
let relay_url = Url::new(relay);
|
||||||
|
if relay_url.is_valid_relay_url() {
|
||||||
|
let db_relay = DbRelay::new(relay_url.inner().to_owned())?;
|
||||||
|
DbRelay::insert(db_relay).await?;
|
||||||
|
|
||||||
|
// Save person_relay
|
||||||
|
DbPersonRelay::upsert_last_suggested_nip05(
|
||||||
|
(*pubkey).into(),
|
||||||
|
relay.inner().to_owned(),
|
||||||
|
Unixtime::now().unwrap().0 as u64,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!("Setup {} relays for {}", relays.len(), &dns_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns user and domain
|
||||||
|
fn parse_dns_id(dns_id: &str) -> Result<(String, String), Error> {
|
||||||
|
let mut parts: Vec<&str> = dns_id.split('@').collect();
|
||||||
|
|
||||||
|
// Add the underscore as a username if they just specified a domain name.
|
||||||
|
if parts.len() == 1 {
|
||||||
|
parts = Vec::from(["_", parts.first().unwrap()])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Require two parts
|
||||||
|
if parts.len() != 2 {
|
||||||
|
Err(Error::InvalidDnsId)
|
||||||
|
} else {
|
||||||
|
let domain = parts.pop().unwrap();
|
||||||
|
let user = parts.pop().unwrap();
|
||||||
|
Ok((user.to_string(), domain.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_nip05(user: &str, domain: &str) -> Result<Nip05, Error> {
|
||||||
|
let nip05_future = reqwest::Client::new()
|
||||||
|
.get(format!(
|
||||||
|
"https://{}/.well-known/nostr.json?name={}",
|
||||||
|
domain, user
|
||||||
|
))
|
||||||
|
.header("Host", domain)
|
||||||
|
.send();
|
||||||
|
let timeout_future = tokio::time::timeout(std::time::Duration::new(15, 0), nip05_future);
|
||||||
|
let response = timeout_future.await??;
|
||||||
|
Ok(response.json::<Nip05>().await?)
|
||||||
|
}
|
@ -8,8 +8,7 @@ use crate::globals::{Globals, GLOBALS};
|
|||||||
use crate::people::People;
|
use crate::people::People;
|
||||||
use minion::Minion;
|
use minion::Minion;
|
||||||
use nostr_types::{
|
use nostr_types::{
|
||||||
Event, EventKind, Id, IdHex, Nip05, PreEvent, PrivateKey, PublicKey, PublicKeyHex, Tag,
|
Event, EventKind, Id, IdHex, PreEvent, PrivateKey, PublicKey, PublicKeyHex, Tag, Unixtime, Url,
|
||||||
Unixtime, Url,
|
|
||||||
};
|
};
|
||||||
use relay_picker::{BestRelay, RelayPicker};
|
use relay_picker::{BestRelay, RelayPicker};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -373,7 +372,7 @@ impl Overlord {
|
|||||||
}
|
}
|
||||||
ToOverlordMessage::FollowNip05(dns_id) => {
|
ToOverlordMessage::FollowNip05(dns_id) => {
|
||||||
let _ = tokio::spawn(async move {
|
let _ = tokio::spawn(async move {
|
||||||
if let Err(e) = Overlord::get_and_follow_nip05(dns_id).await {
|
if let Err(e) = crate::nip05::get_and_follow_nip05(dns_id).await {
|
||||||
tracing::error!("{}", e);
|
tracing::error!("{}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -554,89 +553,6 @@ impl Overlord {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_and_follow_nip05(nip05: String) -> Result<(), Error> {
|
|
||||||
let mut parts: Vec<&str> = nip05.split('@').collect();
|
|
||||||
if parts.len() == 1 {
|
|
||||||
parts = Vec::from(["_", parts.first().unwrap()])
|
|
||||||
}
|
|
||||||
if parts.len() != 2 {
|
|
||||||
return Err(Error::InvalidDnsId);
|
|
||||||
}
|
|
||||||
|
|
||||||
let domain = parts.pop().unwrap();
|
|
||||||
let user = parts.pop().unwrap();
|
|
||||||
let nip05_future = reqwest::Client::new()
|
|
||||||
.get(format!(
|
|
||||||
"https://{}/.well-known/nostr.json?name={}",
|
|
||||||
domain, user
|
|
||||||
))
|
|
||||||
.header("Host", domain)
|
|
||||||
.send();
|
|
||||||
let timeout_future = tokio::time::timeout(std::time::Duration::new(15, 0), nip05_future);
|
|
||||||
let response = timeout_future.await??;
|
|
||||||
let nip05 = response.json::<Nip05>().await?;
|
|
||||||
Overlord::follow_nip05(nip05, user.to_string(), domain.to_string()).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn follow_nip05(nip05: Nip05, user: String, domain: String) -> Result<(), Error> {
|
|
||||||
let dns_id = format!("{}@{}", user, domain);
|
|
||||||
|
|
||||||
let pubkey = match nip05.names.get(&user) {
|
|
||||||
Some(pk) => pk,
|
|
||||||
None => return Err(Error::Nip05KeyNotFound),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save person
|
|
||||||
GLOBALS
|
|
||||||
.people
|
|
||||||
.write()
|
|
||||||
.await
|
|
||||||
.upsert_nip05_validity(
|
|
||||||
&(*pubkey).into(),
|
|
||||||
Some(dns_id.clone()),
|
|
||||||
true,
|
|
||||||
Unixtime::now().unwrap().0 as u64,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Mark as followed
|
|
||||||
GLOBALS
|
|
||||||
.people
|
|
||||||
.write()
|
|
||||||
.await
|
|
||||||
.async_follow(&(*pubkey).into(), true)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
tracing::info!("Followed {}", &dns_id);
|
|
||||||
|
|
||||||
let relays = match nip05.relays.get(pubkey) {
|
|
||||||
Some(relays) => relays,
|
|
||||||
None => return Err(Error::Nip05RelaysNotFound),
|
|
||||||
};
|
|
||||||
|
|
||||||
for relay in relays.iter() {
|
|
||||||
// Save relay
|
|
||||||
let relay_url = Url::new(relay);
|
|
||||||
if relay_url.is_valid_relay_url() {
|
|
||||||
let db_relay = DbRelay::new(relay_url.inner().to_owned())?;
|
|
||||||
DbRelay::insert(db_relay).await?;
|
|
||||||
|
|
||||||
// Save person_relay
|
|
||||||
DbPersonRelay::upsert_last_suggested_nip05(
|
|
||||||
(*pubkey).into(),
|
|
||||||
relay.inner().to_owned(),
|
|
||||||
Unixtime::now().unwrap().0 as u64,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!("Setup {} relays for {}", relays.len(), &dns_id);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn follow_bech32(bech32: String, relay: String) -> Result<(), Error> {
|
async fn follow_bech32(bech32: String, relay: String) -> Result<(), Error> {
|
||||||
let pk = PublicKey::try_from_bech32_string(&bech32)?;
|
let pk = PublicKey::try_from_bech32_string(&bech32)?;
|
||||||
let pkhex: PublicKeyHex = pk.into();
|
let pkhex: PublicKeyHex = pk.into();
|
||||||
|
Loading…
Reference in New Issue
Block a user