From f1b131db0a0abcd66486c12b6e7bec1349d69cf9 Mon Sep 17 00:00:00 2001 From: reya <123083837+reyamir@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:37:47 +0700 Subject: [PATCH] feat: always use ncryptsec --- src-tauri/src/commands/account.rs | 70 +++++++++++----------- src-tauri/src/commands/chat.rs | 4 +- src/commands.ts | 8 +-- src/routes/$account.chats.$id.lazy.tsx | 4 +- src/routes/$account.chats.$id.tsx | 8 ++- src/routes/$account.chats.lazy.tsx | 7 ++- src/routes/import-key.lazy.tsx | 55 +++++++++-------- src/routes/index.lazy.tsx | 81 +++++++++++++++++--------- src/routes/new.lazy.tsx | 33 ++++++----- 9 files changed, 155 insertions(+), 115 deletions(-) diff --git a/src-tauri/src/commands/account.rs b/src-tauri/src/commands/account.rs index 92bf4c0..5407abb 100644 --- a/src-tauri/src/commands/account.rs +++ b/src-tauri/src/commands/account.rs @@ -17,7 +17,7 @@ pub struct EventPayload { #[specta::specta] pub fn get_accounts() -> Vec { let search = Search::new().expect("Unexpected."); - let results = search.by_service("coop"); + let results = search.by_service("Coop Secret Storage"); let list = List::list_credentials(&results, Limit::All); let accounts: HashSet = list.split_whitespace().filter(|v| v.starts_with("npub1")).map(String::from).collect(); @@ -48,7 +48,7 @@ pub async fn get_metadata(id: String, state: State<'_, Nostr>) -> Result Result<(), String> { - let keyring = Entry::new("coop", &id).map_err(|e| e.to_string())?; + let keyring = Entry::new("Coop Secret Storage", &id).map_err(|e| e.to_string())?; let _ = keyring.delete_credential(); Ok(()) @@ -67,7 +67,7 @@ pub async fn create_account( let nsec = keys.secret_key().unwrap().to_bech32().map_err(|e| e.to_string())?; // Save account - let keyring = Entry::new("coop", &npub).unwrap(); + let keyring = Entry::new("Coop Secret Storage", &npub).unwrap(); let _ = keyring.set_password(&nsec); let signer = NostrSigner::Keys(keys); @@ -95,36 +95,34 @@ pub async fn create_account( #[tauri::command] #[specta::specta] pub async fn import_key( - nsec: &str, - password: &str, + key: String, + password: Option, state: State<'_, Nostr>, ) -> Result { - let secret_key = if nsec.starts_with("ncryptsec") { - let encrypted_key = EncryptedSecretKey::from_bech32(nsec).unwrap(); - encrypted_key.to_secret_key(password).map_err(|err| err.to_string()) - } else { - SecretKey::from_bech32(nsec).map_err(|err| err.to_string()) + let client = &state.client; + let secret_key = SecretKey::from_bech32(key).map_err(|err| err.to_string())?; + let keys = Keys::new(secret_key.clone()); + let npub = keys.public_key().to_bech32().unwrap(); + + let enc_bech32 = match password { + Some(pw) => { + let enc = EncryptedSecretKey::new(&secret_key, pw, 16, KeySecurity::Medium) + .map_err(|err| err.to_string())?; + + enc.to_bech32().map_err(|err| err.to_string())? + } + None => secret_key.to_bech32().map_err(|err| err.to_string())?, }; - match secret_key { - Ok(val) => { - let nostr_keys = Keys::new(val); - let npub = nostr_keys.public_key().to_bech32().unwrap(); - let nsec = nostr_keys.secret_key().unwrap().to_bech32().unwrap(); + let keyring = Entry::new("Coop Secret Storage", &npub).unwrap(); + let _ = keyring.set_password(&enc_bech32); - let keyring = Entry::new("coop", &npub).unwrap(); - let _ = keyring.set_password(&nsec); + let signer = NostrSigner::Keys(keys); - let signer = NostrSigner::Keys(nostr_keys); - let client = &state.client; + // Update client's signer + client.set_signer(Some(signer)).await; - // Update client's signer - client.set_signer(Some(signer)).await; - - Ok(npub) - } - Err(msg) => Err(msg), - } + Ok(npub) } #[tauri::command] @@ -143,7 +141,7 @@ pub async fn connect_account(uri: &str, state: State<'_, Nostr>) -> Result { - let keyring = Entry::new("coop", &remote_npub).unwrap(); + let keyring = Entry::new("Coop Secret Storage", &remote_npub).unwrap(); let _ = keyring.set_password(&app_secret); // Update signer @@ -220,21 +218,23 @@ pub async fn set_inbox(relays: Vec, state: State<'_, Nostr>) -> Result<( #[tauri::command] #[specta::specta] pub async fn login( - id: String, + account: String, + password: String, state: State<'_, Nostr>, handle: tauri::AppHandle, ) -> Result { let client = &state.client; - let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?; - let hex = public_key.to_hex(); - let keyring = Entry::new("coop", &id).map_err(|e| e.to_string())?; + let keyring = Entry::new("Coop Secret Storage", &account).map_err(|e| e.to_string())?; - let password = match keyring.get_password() { + let bech32 = match keyring.get_password() { Ok(pw) => pw, - Err(_) => return Err("Cancelled".into()), + Err(_) => return Err("Action have been cancelled".into()), }; - let keys = Keys::parse(password).map_err(|e| e.to_string())?; + let ncryptsec = EncryptedSecretKey::from_bech32(bech32).map_err(|e| e.to_string())?; + let secret_key = ncryptsec.to_secret_key(password).map_err(|e| e.to_string())?; + let keys = Keys::new(secret_key); + let public_key = keys.public_key(); let signer = NostrSigner::Keys(keys); // Update signer @@ -363,5 +363,5 @@ pub async fn login( .await }); - Ok(hex) + Ok(public_key.to_hex()) } diff --git a/src-tauri/src/commands/chat.rs b/src-tauri/src/commands/chat.rs index f3ba8a9..5bd5c5d 100644 --- a/src-tauri/src/commands/chat.rs +++ b/src-tauri/src/commands/chat.rs @@ -15,7 +15,7 @@ pub async fn get_chats(state: State<'_, Nostr>) -> Result, String> { let filter = Filter::new().kind(Kind::PrivateDirectMessage).pubkey(public_key); - match client.database().query(vec![filter.clone()], Order::Desc).await { + match client.database().query(vec![filter], Order::Asc).await { Ok(events) => { let ev = events .into_iter() @@ -38,7 +38,7 @@ pub async fn get_chat_messages(id: String, state: State<'_, Nostr>) -> Result> { +async login(account: string, password: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("login", { id }) }; + return { status: "ok", data: await TAURI_INVOKE("login", { account, password }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; @@ -28,9 +28,9 @@ try { else return { status: "error", error: e as any }; } }, -async importKey(nsec: string, password: string) : Promise> { +async importKey(key: string, password: string | null) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("import_key", { nsec, password }) }; + return { status: "ok", data: await TAURI_INVOKE("import_key", { key, password }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; diff --git a/src/routes/$account.chats.$id.lazy.tsx b/src/routes/$account.chats.$id.lazy.tsx index b241ae2..7871a58 100644 --- a/src/routes/$account.chats.$id.lazy.tsx +++ b/src/routes/$account.chats.$id.lazy.tsx @@ -291,7 +291,7 @@ function List() { function Form() { const { id } = Route.useParams(); - const { inbox } = Route.useRouteContext(); + const inboxRelays = Route.useLoaderData(); const [newMessage, setNewMessage] = useState(""); const [isPending, startTransition] = useTransition(); @@ -313,7 +313,7 @@ function Form() { return (
- {!inbox.length ? ( + {!inboxRelays.length ? (
This user doesn't have inbox relays. You cannot send messages to them.
diff --git a/src/routes/$account.chats.$id.tsx b/src/routes/$account.chats.$id.tsx index 4ab3f62..b3a652f 100644 --- a/src/routes/$account.chats.$id.tsx +++ b/src/routes/$account.chats.$id.tsx @@ -2,8 +2,10 @@ import { createFileRoute } from "@tanstack/react-router"; import { invoke } from "@tauri-apps/api/core"; export const Route = createFileRoute("/$account/chats/$id")({ - beforeLoad: async ({ params }) => { - const inbox: string[] = await invoke("connect_inbox", { id: params.id }); - return { inbox }; + loader: async ({ params }) => { + const inboxRelays: string[] = await invoke("connect_inbox", { + id: params.id, + }); + return inboxRelays; }, }); diff --git a/src/routes/$account.chats.lazy.tsx b/src/routes/$account.chats.lazy.tsx index 0b61948..504d044 100644 --- a/src/routes/$account.chats.lazy.tsx +++ b/src/routes/$account.chats.lazy.tsx @@ -17,6 +17,7 @@ import { Link, Outlet, createLazyFileRoute } from "@tanstack/react-router"; import { listen } from "@tauri-apps/api/event"; import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu"; import { message } from "@tauri-apps/plugin-dialog"; +import { open } from "@tauri-apps/plugin-shell"; import type { NostrEvent } from "nostr-tools"; import { useCallback, useEffect, useState, useTransition } from "react"; @@ -362,8 +363,8 @@ function Compose() { > - - + + @@ -406,7 +407,7 @@ function CurrentUser() { }), MenuItem.new({ text: "Feedback", - action: () => navigate({ to: "/" }), + action: async () => await open("https://github.com/lumehq/coop/issues"), }), PredefinedMenuItem.new({ item: "Separator" }), MenuItem.new({ diff --git a/src/routes/import-key.lazy.tsx b/src/routes/import-key.lazy.tsx index 1ecc5a7..a9ea084 100644 --- a/src/routes/import-key.lazy.tsx +++ b/src/routes/import-key.lazy.tsx @@ -25,14 +25,22 @@ function Screen() { const submit = async () => { startTransition(async () => { - if (!key.startsWith("nsec1")) { + if (!key.startsWith("nsec1") && !key.startsWith("ncryptsec")) { await message( "You need to enter a valid private key starts with nsec or ncryptsec", - { title: "Import Key", kind: "info" }, + { title: "Login", kind: "info" }, ); return; } + if (key.startsWith("nsec1") && !password.length) { + await message("You must set password to secure your key", { + title: "Login", + kind: "info", + }); + return; + } + const res = await commands.importKey(key, password); if (res.status === "ok") { @@ -63,47 +71,48 @@ function Screen() { className="flex flex-col gap-3 p-3 rounded-xl overflow-hidden" shadow > -
+
-
setKey(e.target.value)} - className="pl-3 pr-12 rounded-lg w-full h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none" + className="pl-3 pr-12 rounded-lg w-full h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none placeholder:text-neutral-400 dark:placeholder:text-neutral-600" />
-
- - setPassword(e.target.value)} - className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none" - /> -
+ {key.length && !key.startsWith("ncryptsec") ? ( +
+ + setPassword(e.target.value)} + className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none" + /> +
+ ) : null}
- )} +
+ {value === account ? ( + isPending ? ( + + ) : ( + + ) + ) : null}
))} diff --git a/src/routes/new.lazy.tsx b/src/routes/new.lazy.tsx index c5f2b32..a018878 100644 --- a/src/routes/new.lazy.tsx +++ b/src/routes/new.lazy.tsx @@ -16,27 +16,28 @@ function Screen() { Direct Message on Nostr.
-
+
Create a new identity - - Login with Private Key - - {/* - - Login with Private Key (not recommended) - - */} +
+
+ {/* + Login with Nostr Connect + */} + + Login with Private Key + +