feat(signer): adopt real display name/picture for paired NIP-46 identities
A paired profile was stored under the generic pairing label (or a bare npub). adopt_identity now does a best-effort, 3s-capped kind-0 metadata lookup for the learned identity and stores display_name/name plus picture/nip05 on the profile row, falling back to the pairing label when relays are unavailable.
This commit is contained in:
parent
9cfab4bce6
commit
3d5302fbf3
2 changed files with 48 additions and 3 deletions
|
|
@ -561,7 +561,7 @@ fn publish_metadata_blocking(
|
|||
|
||||
/// Best-effort lookup of the account's latest kind-0 metadata. Import must
|
||||
/// still succeed when relays are unavailable, so lookup failures are ignored.
|
||||
fn fetch_profile_metadata(public_key: &PublicKey, relay_urls: &[String]) -> Option<Metadata> {
|
||||
pub fn fetch_profile_metadata(public_key: &PublicKey, relay_urls: &[String]) -> Option<Metadata> {
|
||||
if relay_urls.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -793,7 +793,7 @@ impl Nip46ClientSigner {
|
|||
let message = message.into();
|
||||
eprintln!("[nip46] session failed: {message}");
|
||||
if let Ok(mut inner) = self.inner.try_lock() {
|
||||
inner.phase = Nip46Phase::Error(message.into());
|
||||
inner.phase = Nip46Phase::Error(message);
|
||||
inner.task = None;
|
||||
inner.client = None;
|
||||
inner.conversation_key = None;
|
||||
|
|
@ -1450,13 +1450,58 @@ impl Nip46ClientSigner {
|
|||
.to_bech32()
|
||||
.map_err(|e| format!("Could not encode identity npub: {e}"))?;
|
||||
|
||||
// Best-effort: look up the identity's kind-0 metadata so the profile
|
||||
// row carries the real display name / picture / nip05 instead of a
|
||||
// bare npub or the generic pairing label. Relay hiccups fall back to
|
||||
// the pairing label — the connection must not depend on them.
|
||||
let relays_for_meta = {
|
||||
let app = self.app.lock().await;
|
||||
crate::relays::enabled_urls(&app.settings)
|
||||
};
|
||||
let meta_npub = identity;
|
||||
let metadata = match tokio::time::timeout(
|
||||
Duration::from_secs(3),
|
||||
tokio::task::spawn_blocking(move || {
|
||||
profiles::fetch_profile_metadata(&meta_npub, &relays_for_meta)
|
||||
}),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(joined) => joined.ok().flatten(),
|
||||
Err(_elapsed) => None,
|
||||
};
|
||||
let display_label = metadata
|
||||
.as_ref()
|
||||
.and_then(|m| m.display_name.as_deref().or(m.name.as_deref()))
|
||||
.map(str::trim)
|
||||
.filter(|name| !name.is_empty())
|
||||
.map(str::to_string)
|
||||
.unwrap_or(label);
|
||||
|
||||
// Persist: profile row for the identity, connection + secret store
|
||||
// re-keyed under it. Refuses (fails the handshake) if the identity
|
||||
// collides with a local profile.
|
||||
{
|
||||
let mut app = self.app.lock().await;
|
||||
profiles::store_remote_profile(&mut app.vault, &identity_npub, label)
|
||||
profiles::store_remote_profile(&mut app.vault, &identity_npub, display_label)
|
||||
.map_err(|e| e.message().to_string())?;
|
||||
// Carry the looked-up metadata (picture / nip05) onto the row so
|
||||
// the profile shows its real identity, not just a name.
|
||||
if let Some(meta) = &metadata {
|
||||
if let Some(row) = app
|
||||
.vault
|
||||
.profiles
|
||||
.iter_mut()
|
||||
.find(|p| p.public_key == identity_npub)
|
||||
{
|
||||
if row.picture.is_none() {
|
||||
row.picture = meta.picture.clone();
|
||||
}
|
||||
if row.nip05.is_none() {
|
||||
row.nip05 = meta.nip05.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Re-key the stored secret under the identity npub so the
|
||||
// connection row, VaultRef, and secret store all agree.
|
||||
let connect_ref = crate::signer::VaultRef::from_connection(&connection);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue