Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit 2b296fb

Browse files
authored
Merge pull request #1105 from MutinyWallet/check-lnurl-name
Check LNURL name
2 parents 23ec5f3 + 30545f3 commit 2b296fb

3 files changed

Lines changed: 100 additions & 14 deletions

File tree

mutiny-core/src/hermes.rs

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ pub struct HermesClient<S: MutinyStorage> {
6464
pub(crate) federations: Arc<RwLock<HashMap<FederationId, Arc<FederationClient<S>>>>>,
6565
blind_auth: Arc<BlindAuthClient<S>>,
6666
base_url: String,
67+
// bool represents whether or not it was successfully checked
68+
current_address: Arc<RwLock<(Option<String>, bool)>>,
6769
storage: S,
6870
pub logger: Arc<MutinyLogger>,
6971
pub stop: Arc<AtomicBool>,
@@ -100,8 +102,6 @@ impl<S: MutinyStorage> HermesClient<S> {
100102
.await
101103
.expect("Failed to add relays");
102104

103-
// TODO need to store the fact that we have a LNURL or not...
104-
105105
Ok(Self {
106106
dm_key: keys,
107107
public_key,
@@ -110,6 +110,7 @@ impl<S: MutinyStorage> HermesClient<S> {
110110
base_url,
111111
federations,
112112
blind_auth,
113+
current_address: Arc::new(RwLock::new((None, false))),
113114
storage: storage.clone(),
114115
logger,
115116
stop,
@@ -120,25 +121,59 @@ impl<S: MutinyStorage> HermesClient<S> {
120121
/// This should only error if there's an initial unrecoverable error
121122
/// Otherwise it will loop in the background until a stop signal
122123
pub fn start(&self, profile_key: Option<Keys>) -> Result<(), MutinyError> {
123-
let logger = self.logger.clone();
124-
let stop = self.stop.clone();
125-
let client = self.client.clone();
126-
let public_key = self.public_key;
127-
let storage = self.storage.clone();
128-
let dm_key = self.dm_key.clone();
129-
let federations = self.federations.clone();
130-
131124
// if we haven't synced before, use now and save to storage
132-
let last_sync_time = storage.get_dm_sync_time(true)?;
125+
let last_sync_time = self.storage.get_dm_sync_time(true)?;
133126
let time_stamp = match last_sync_time {
134127
None => {
135128
let now = Timestamp::now();
136-
storage.set_dm_sync_time(now.as_u64(), true)?;
129+
self.storage.set_dm_sync_time(now.as_u64(), true)?;
137130
now
138131
}
139132
Some(time) => Timestamp::from(time + 1), // add one so we get only new events
140133
};
141134

135+
// check to see if we currently have an address
136+
let logger_check_clone = self.logger.clone();
137+
let stop_check_clone = self.stop.clone();
138+
let http_client_check_clone = self.http_client.clone();
139+
let public_key_check_clone = self.public_key;
140+
let base_url_check_clone = self.base_url.clone();
141+
let current_address_check_clone = self.current_address.clone();
142+
utils::spawn(async move {
143+
loop {
144+
if stop_check_clone.load(Ordering::Relaxed) {
145+
break;
146+
};
147+
148+
match check_hermes_name_for_pubkey(
149+
&http_client_check_clone,
150+
&base_url_check_clone,
151+
public_key_check_clone,
152+
)
153+
.await
154+
{
155+
Ok(o) => {
156+
let mut c = current_address_check_clone.write().await;
157+
log_info!(logger_check_clone, "checked lightning address: {o:?}");
158+
*c = (o, true);
159+
break;
160+
}
161+
Err(e) => {
162+
log_error!(logger_check_clone, "error checking lightning address: {e}");
163+
}
164+
};
165+
166+
utils::sleep(1_000).await;
167+
}
168+
});
169+
170+
let logger = self.logger.clone();
171+
let stop = self.stop.clone();
172+
let client = self.client.clone();
173+
let public_key = self.public_key;
174+
let storage = self.storage.clone();
175+
let dm_key = self.dm_key.clone();
176+
let federations = self.federations.clone();
142177
utils::spawn(async move {
143178
loop {
144179
if stop.load(Ordering::Relaxed) {
@@ -243,21 +278,41 @@ impl<S: MutinyStorage> HermesClient<S> {
243278

244279
// send the register request
245280
let req = RegisterRequest {
246-
name: Some(name),
281+
name: Some(name.clone()),
247282
pubkey: self.public_key.to_string(),
248283
federation_invite_code: federation_identity.invite_code.to_string(),
249284
msg: nonce.to_message(),
250285
sig: unblinded_sig,
251286
};
252287
register_name(&self.http_client.clone(), &self.base_url, req).await?;
253-
// TODO store the fact that this succeeded
288+
289+
{
290+
let mut c = self.current_address.write().await;
291+
log_info!(
292+
self.logger,
293+
"registered lightning address: {}",
294+
name.clone()
295+
);
296+
*c = (Some(name), true);
297+
}
254298

255299
// Mark the token as spent successfully
256300
self.blind_auth.used_token(available_paid_token).await?;
257301

258302
Ok(())
259303
}
260304

305+
pub async fn check_username(&self) -> Result<Option<String>, MutinyError> {
306+
match self.current_address.read().await.clone() {
307+
(None, false) => Err(MutinyError::ConnectionFailed),
308+
(Some(n), true) => Ok(Some(n)),
309+
(None, true) => Ok(None),
310+
_ => {
311+
unreachable!("can't have some and false")
312+
}
313+
}
314+
}
315+
261316
async fn get_first_federation(&self) -> Option<FederationIdentity> {
262317
let federations = self.federations.read().await;
263318
match federations.iter().next() {
@@ -279,6 +334,24 @@ fn find_hermes_token(
279334
.find(|token| token.service_id == service_id && token.plan_id == plan_id)
280335
}
281336

337+
async fn check_hermes_name_for_pubkey(
338+
http_client: &reqwest::Client,
339+
base_url: &str,
340+
pubkey: nostr::PublicKey,
341+
) -> Result<Option<String>, MutinyError> {
342+
let url = Url::parse(&format!("{}/v1/check-pubkey/{pubkey}", base_url,))
343+
.map_err(|_| MutinyError::ConnectionFailed)?;
344+
let request = http_client.request(Method::GET, url);
345+
346+
let res = utils::fetch_with_timeout(http_client, request.build().expect("should build req"))
347+
.await?
348+
.json::<Option<String>>()
349+
.await
350+
.map_err(|_| MutinyError::ConnectionFailed)?;
351+
352+
Ok(res)
353+
}
354+
282355
async fn check_name_request(
283356
http_client: &reqwest::Client,
284357
base_url: &str,

mutiny-core/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2776,6 +2776,14 @@ impl<S: MutinyStorage> MutinyWallet<S> {
27762776
}
27772777
}
27782778

2779+
pub async fn check_lnurl_name(&self) -> Result<Option<String>, MutinyError> {
2780+
if let Some(hermes_client) = self.hermes_client.as_ref() {
2781+
hermes_client.check_username().await
2782+
} else {
2783+
Err(MutinyError::NotFound)
2784+
}
2785+
}
2786+
27792787
/// Starts up the hermes client if available
27802788
pub fn start_hermes(&self, profile_key: Option<Keys>) -> Result<(), MutinyError> {
27812789
if let Some(hermes_client) = self.hermes_client.as_ref() {

mutiny-wasm/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,11 @@ impl MutinyWallet {
19621962
Ok(self.inner.reserve_lnurl_name(name).await?)
19631963
}
19641964

1965+
/// Checks the registered username for the user
1966+
pub async fn check_lnurl_name(&self) -> Result<Option<String>, MutinyJsError> {
1967+
Ok(self.inner.check_lnurl_name().await?)
1968+
}
1969+
19651970
/// Resets the scorer and network graph. This can be useful if you get stuck in a bad state.
19661971
#[wasm_bindgen]
19671972
pub async fn reset_router(&self) -> Result<(), MutinyJsError> {

0 commit comments

Comments
 (0)