chore: update gpui and nostr sdk
This commit is contained in:
@@ -12,7 +12,7 @@ gpui.workspace = true
|
||||
nostr-sdk.workspace = true
|
||||
anyhow.workspace = true
|
||||
smol.workspace = true
|
||||
reqwest.workspace = true
|
||||
log.workspace = true
|
||||
|
||||
tempfile = "3.19.1"
|
||||
reqwest = { version = "0.12", features = ["stream"] }
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::sync::Arc;
|
||||
use anyhow::{anyhow, Error};
|
||||
use chrono::{Local, TimeZone};
|
||||
use common::profile::RenderProfile;
|
||||
use common::{compare, room_hash};
|
||||
use global::shared_state;
|
||||
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task, Window};
|
||||
use identity::Identity;
|
||||
@@ -79,7 +78,7 @@ impl Room {
|
||||
///
|
||||
/// A new Room instance with information extracted from the event
|
||||
pub fn new(event: &Event) -> Self {
|
||||
let id = room_hash(event);
|
||||
let id = common::room_hash(event);
|
||||
let created_at = event.created_at;
|
||||
|
||||
// Get all pubkeys from the event's tags
|
||||
@@ -405,7 +404,7 @@ impl Room {
|
||||
let mut other_pubkeys = ev.tags.public_keys().copied().collect::<Vec<_>>();
|
||||
other_pubkeys.push(ev.pubkey);
|
||||
// Check if the event is from a member of the room
|
||||
compare(&other_pubkeys, &pubkeys)
|
||||
common::compare(&other_pubkeys, &pubkeys)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
||||
@@ -10,12 +10,14 @@ global = { path = "../global" }
|
||||
gpui.workspace = true
|
||||
nostr-connect.workspace = true
|
||||
nostr-sdk.workspace = true
|
||||
nostr.workspace = true
|
||||
anyhow.workspace = true
|
||||
itertools.workspace = true
|
||||
chrono.workspace = true
|
||||
smallvec.workspace = true
|
||||
smol.workspace = true
|
||||
futures.workspace = true
|
||||
reqwest.workspace = true
|
||||
|
||||
webbrowser = "1.0.4"
|
||||
qrcode-generator = "5.0.0"
|
||||
|
||||
@@ -2,23 +2,43 @@ use std::collections::HashSet;
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use gpui::{Image, ImageFormat};
|
||||
use itertools::Itertools;
|
||||
use nostr_sdk::prelude::*;
|
||||
use qrcode_generator::QrCodeEcc;
|
||||
use reqwest::Client as ReqClient;
|
||||
|
||||
pub mod debounced_delay;
|
||||
pub mod handle_auth;
|
||||
pub mod profile;
|
||||
|
||||
pub async fn nip96_upload(
|
||||
client: &Client,
|
||||
upload_to: Url,
|
||||
file: Vec<u8>,
|
||||
) -> anyhow::Result<Url, anyhow::Error> {
|
||||
let signer = client.signer().await?;
|
||||
pub async fn verify_nip05(public_key: PublicKey, address: &str) -> Result<bool, Error> {
|
||||
let req_client = ReqClient::new();
|
||||
let address = Nip05Address::parse(address)?;
|
||||
let res = req_client.get(address.url().to_string()).send().await?;
|
||||
let json: Value = res.json().await?;
|
||||
let verify = nip05::verify_from_json(&public_key, &address, &json);
|
||||
|
||||
let config: ServerConfig = nip96::get_server_config(upload_to.to_owned(), None).await?;
|
||||
Ok(verify)
|
||||
}
|
||||
|
||||
pub async fn nip05_profile(address: &str) -> Result<Nip05Profile, Error> {
|
||||
let req_client = ReqClient::new();
|
||||
let address = Nip05Address::parse(address)?;
|
||||
let res = req_client.get(address.url().to_string()).send().await?;
|
||||
let json: Value = res.json().await?;
|
||||
|
||||
if let Ok(profile) = Nip05Profile::from_json(&address, &json) {
|
||||
Ok(profile)
|
||||
} else {
|
||||
Err(anyhow!("Failed to get NIP-05 profile"))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn nip96_upload(client: &Client, server: Url, file: Vec<u8>) -> Result<Url, Error> {
|
||||
let signer = client.signer().await?;
|
||||
let config = nip96::get_server_config(server.to_owned(), None).await?;
|
||||
let url = nip96::upload_data(&signer, &config, file, None, None).await?;
|
||||
|
||||
Ok(url)
|
||||
@@ -26,10 +46,10 @@ pub async fn nip96_upload(
|
||||
|
||||
pub fn room_hash(event: &Event) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
let mut pubkeys: Vec<&PublicKey> = vec![];
|
||||
let mut pubkeys: Vec<PublicKey> = vec![];
|
||||
|
||||
// Add all public keys from event
|
||||
pubkeys.push(&event.pubkey);
|
||||
pubkeys.push(event.pubkey);
|
||||
pubkeys.extend(event.tags.public_keys().collect::<Vec<_>>());
|
||||
|
||||
// Generate unique hash
|
||||
|
||||
@@ -24,6 +24,7 @@ reqwest_client.workspace = true
|
||||
|
||||
nostr-connect.workspace = true
|
||||
nostr-sdk.workspace = true
|
||||
nostr.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
@@ -7,8 +7,8 @@ use global::constants::{DEFAULT_MODAL_WIDTH, DEFAULT_SIDEBAR_WIDTH};
|
||||
use global::shared_state;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, impl_internal_actions, px, relative, App, AppContext, Axis, Context, Entity, IntoElement,
|
||||
ParentElement, Render, Styled, Subscription, Task, Window,
|
||||
div, px, relative, Action, App, AppContext, Axis, Context, Entity, IntoElement, ParentElement,
|
||||
Render, Styled, Subscription, Task, Window,
|
||||
};
|
||||
use identity::Identity;
|
||||
use nostr_connect::prelude::*;
|
||||
@@ -25,8 +25,6 @@ use ui::{ContextModal, IconName, Root, Sizable, StyledExt, TitleBar};
|
||||
use crate::views::chat::{self, Chat};
|
||||
use crate::views::{login, new_account, onboarding, preferences, sidebar, startup, welcome};
|
||||
|
||||
impl_internal_actions!(dock, [ToggleModal]);
|
||||
|
||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<ChatSpace> {
|
||||
ChatSpace::new(window, cx)
|
||||
}
|
||||
@@ -56,7 +54,8 @@ pub enum ModalKind {
|
||||
SetupRelay,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||
#[derive(Action, Clone, PartialEq, Eq, Deserialize)]
|
||||
#[action(namespace = modal, no_json)]
|
||||
pub struct ToggleModal {
|
||||
pub modal: ModalKind,
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ use common::profile::RenderProfile;
|
||||
use global::shared_state;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, img, impl_internal_actions, list, px, red, relative, rems, svg, white, AnyElement, App,
|
||||
AppContext, ClipboardItem, Context, Div, Element, Empty, Entity, EventEmitter, Flatten,
|
||||
FocusHandle, Focusable, InteractiveElement, IntoElement, ListAlignment, ListState, ObjectFit,
|
||||
ParentElement, PathPromptOptions, Render, RetainAllImageCache, SharedString,
|
||||
StatefulInteractiveElement, Styled, StyledImage, Subscription, Window,
|
||||
div, img, list, px, red, relative, rems, svg, white, Action, AnyElement, App, AppContext,
|
||||
ClipboardItem, Context, Div, Element, Empty, Entity, EventEmitter, Flatten, FocusHandle,
|
||||
Focusable, InteractiveElement, IntoElement, ListAlignment, ListState, ObjectFit, ParentElement,
|
||||
PathPromptOptions, Render, RetainAllImageCache, SharedString, StatefulInteractiveElement,
|
||||
Styled, StyledImage, Subscription, Window,
|
||||
};
|
||||
use identity::Identity;
|
||||
use itertools::Itertools;
|
||||
@@ -38,11 +38,10 @@ use ui::{
|
||||
|
||||
use crate::views::subject;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||
#[derive(Action, Clone, PartialEq, Eq, Deserialize)]
|
||||
#[action(namespace = chat, no_json)]
|
||||
pub struct ChangeSubject(pub String);
|
||||
|
||||
impl_internal_actions!(chat, [ChangeSubject]);
|
||||
|
||||
pub fn init(room: Entity<Room>, window: &mut Window, cx: &mut App) -> Arc<Entity<Chat>> {
|
||||
Arc::new(Chat::new(room, window, cx))
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@ use std::time::Duration;
|
||||
use anyhow::{anyhow, Error};
|
||||
use chats::room::{Room, RoomKind};
|
||||
use chats::ChatRegistry;
|
||||
use common::nip05_profile;
|
||||
use common::profile::RenderProfile;
|
||||
use global::shared_state;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, img, impl_internal_actions, px, red, relative, uniform_list, App, AppContext, Context,
|
||||
Entity, InteractiveElement, IntoElement, ParentElement, Render, SharedString,
|
||||
div, img, px, red, relative, uniform_list, App, AppContext, Context, Entity,
|
||||
InteractiveElement, IntoElement, ParentElement, Render, SharedString,
|
||||
StatefulInteractiveElement, Styled, Subscription, Task, TextAlign, Window,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use nostr_sdk::prelude::*;
|
||||
use serde::Deserialize;
|
||||
use settings::AppSettings;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use smol::Timer;
|
||||
@@ -28,11 +28,6 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<Compose> {
|
||||
cx.new(|cx| Compose::new(window, cx))
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||
struct SelectContact(PublicKey);
|
||||
|
||||
impl_internal_actions!(contacts, [SelectContact]);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Contact {
|
||||
profile: Profile,
|
||||
@@ -245,15 +240,14 @@ impl Compose {
|
||||
|
||||
let task: Task<Result<Contact, anyhow::Error>> = if content.contains("@") {
|
||||
cx.background_spawn(async move {
|
||||
let (tx, rx) = oneshot::channel::<Nip05Profile>();
|
||||
let (tx, rx) = oneshot::channel::<Option<Nip05Profile>>();
|
||||
|
||||
nostr_sdk::async_utility::task::spawn(async move {
|
||||
if let Ok(profile) = nip05::profile(&content, None).await {
|
||||
tx.send(profile).ok();
|
||||
}
|
||||
let profile = nip05_profile(&content).await.ok();
|
||||
tx.send(profile).ok();
|
||||
});
|
||||
|
||||
if let Ok(profile) = rx.await {
|
||||
if let Ok(Some(profile)) = rx.await {
|
||||
let public_key = profile.public_key;
|
||||
let metadata = shared_state()
|
||||
.client()
|
||||
|
||||
@@ -7,6 +7,7 @@ use chats::room::{Room, RoomKind};
|
||||
use chats::{ChatRegistry, RoomEmitter};
|
||||
use common::debounced_delay::DebouncedDelay;
|
||||
use common::profile::RenderProfile;
|
||||
use common::verify_nip05;
|
||||
use element::DisplayRoom;
|
||||
use global::constants::{DEFAULT_MODAL_WIDTH, SEARCH_RELAYS};
|
||||
use global::shared_state;
|
||||
@@ -184,13 +185,8 @@ impl Sidebar {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(verified) = nip05::verify(&event.pubkey, target, None).await else {
|
||||
// Skip if NIP-05 verification fails
|
||||
continue;
|
||||
};
|
||||
|
||||
if !verified {
|
||||
// Skip if NIP-05 is not valid
|
||||
if !verify_nip05(event.pubkey, target).await.unwrap_or(false) {
|
||||
// Skip if NIP-05 is not valid or failed to verify
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use gpui::{actions, impl_internal_actions};
|
||||
use gpui::{actions, Action};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||
#[derive(Clone, Action, PartialEq, Eq, Deserialize)]
|
||||
#[action(namespace = list, no_json)]
|
||||
pub struct Confirm {
|
||||
/// Is confirm with secondary.
|
||||
pub secondary: bool,
|
||||
}
|
||||
|
||||
actions!(list, [Cancel, SelectPrev, SelectNext]);
|
||||
impl_internal_actions!(list, [Confirm]);
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, impl_internal_actions, px, App, AppContext, Corner, Element, InteractiveElement,
|
||||
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled,
|
||||
WeakEntity, Window,
|
||||
div, px, Action, App, AppContext, Corner, Element, InteractiveElement, IntoElement,
|
||||
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled, WeakEntity,
|
||||
Window,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use theme::ActiveTheme;
|
||||
@@ -14,11 +14,10 @@ use crate::input::InputState;
|
||||
use crate::popover::{Popover, PopoverContent};
|
||||
use crate::Icon;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Deserialize)]
|
||||
#[derive(Action, PartialEq, Clone, Debug, Deserialize)]
|
||||
#[action(namespace = emoji, no_json)]
|
||||
pub struct EmitEmoji(pub SharedString);
|
||||
|
||||
impl_internal_actions!(emoji, [EmitEmoji]);
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct EmojiPicker {
|
||||
icon: Option<Icon>,
|
||||
|
||||
@@ -4,8 +4,8 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
actions, div, impl_internal_actions, point, px, App, AppContext, Bounds, ClipboardItem,
|
||||
Context, DefiniteLength, Entity, EntityInputHandler, EventEmitter, FocusHandle, Focusable,
|
||||
actions, div, point, px, Action, App, AppContext, Bounds, ClipboardItem, Context,
|
||||
DefiniteLength, Entity, EntityInputHandler, EventEmitter, FocusHandle, Focusable,
|
||||
InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, ScrollHandle,
|
||||
ScrollWheelEvent, SharedString, Styled as _, Subscription, UTF16Selection, Window, WrappedLine,
|
||||
@@ -24,14 +24,13 @@ use crate::history::History;
|
||||
use crate::scroll::ScrollbarState;
|
||||
use crate::Root;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||
#[derive(Action, Clone, PartialEq, Eq, Deserialize)]
|
||||
#[action(namespace = input, no_json)]
|
||||
pub struct Enter {
|
||||
/// Is confirm with secondary.
|
||||
pub secondary: bool,
|
||||
}
|
||||
|
||||
impl_internal_actions!(input, [Enter]);
|
||||
|
||||
actions!(
|
||||
input,
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user