aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-01-07 14:42:03 -0800
committerAdam Soltys <[email protected]>2025-01-07 14:42:03 -0800
commit2358d1bf39c34a508db6c50f0f6312ee411a8a17 (patch)
treec1a592710013c0db2f4d992f6884f4fd371f125d /src/components
parent493cb3a3504fdc2791d47fd032f5ac9d2ccc66b7 (diff)
downloadcoinos-ui-2358d1bf39c34a508db6c50f0f6312ee411a8a17.tar.gz
coinos-ui-2358d1bf39c34a508db6c50f0f6312ee411a8a17.zip
nostr signin
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Nostr.svelte260
1 files changed, 94 insertions, 166 deletions
diff --git a/src/components/Nostr.svelte b/src/components/Nostr.svelte
index 6445c4c1..0765f440 100644
--- a/src/components/Nostr.svelte
+++ b/src/components/Nostr.svelte
@@ -8,6 +8,7 @@
import { encrypt, decrypt, getConversationKey } from "nostr-tools/nip44";
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
import {
+ nip04,
nip19,
getEventHash,
finalizeEvent,
@@ -16,22 +17,29 @@
} from "nostr-tools";
import { AmberClipboardSigner } from "applesauce-signer";
- import { focus, fail, post } from "$lib/utils";
+ import { copy, focus, fail, post } from "$lib/utils";
import { password as pw, passwordPrompt } from "$lib/store";
+ // import { PUBLIC_COINOS_RELAY as relayUrl } from "$env/static/public";
+ const relayUrl = "wss://relay.nsec.app";
- let { id, redirect, token, nostrSignin } = $props();
+ let { id, redirect, token, nostrSignin = $bindable() } = $props();
let extension = $state();
onMount(() => {
if (browser && window.nostr) extension = true;
});
- let cancel = () => (nostrSignin = false);
+ let cancel = () => {
+ nostrSignin = false;
+ showNsec = false;
+ pubkey = undefined;
+ connectUrl = undefined;
+ };
let sk = $state();
let ck = $state();
let pk = $state();
- let relay = $state();
+ let pubkey = $state();
let signer = $derived(
browser &&
@@ -41,137 +49,65 @@
);
let connectUrl = $state();
- // let bunkerConnect = async () => {
- // sk = generateSecretKey();
- // console.log("SK", bytesToHex(sk));
- // let pubkey = getPublicKey(sk);
- // console.log("PUBKEY", pubkey);
- //
- // const url = new URL(bunker);
- // const secret = url.searchParams.get("secret");
- // console.log("URL", url);
- // pk = url.host || url.pathname.replace("//", "");
- // console.log("PK", pk);
- // const relayUrl = url.searchParams.get("relay");
- // relay = await Relay.connect(relayUrl);
- // console.log("connecting to", relayUrl);
- //
- // ck = getConversationKey(sk, pk);
- //
- // console.log("PK", pk);
- // console.log("CK", bytesToHex(ck));
- //
- // let connect = {
- // id: crypto.randomUUID(),
- // method: "connect",
- // params: [pk, secret, "get_public_key,sign_event"],
- // };
- //
- // let event = {
- // created_at: Math.round(Date.now() / 1000),
- // kind: 24133,
- // pubkey,
- // content: encrypt(JSON.stringify(connect), ck),
- // tags: [["p", pk]],
- // };
- //
- // let signedEvent = finalizeEvent(event, sk);
- // console.log("publishing connection event", signedEvent);
- // await relay.publish(signedEvent);
- //
- // const sub = relay.subscribe([{ kinds: [24133], "#p": [pubkey] }], {
- // async onevent(ev) {
- // console.log("got event:", ev);
- // try {
- // console.log(decrypt(ev.content, ck));
- // } catch (e) {
- // console.log(e);
- // }
- // },
- // });
- // };
-
- let getPubkey = async () => {
- let pubkey = getPublicKey(sk);
- let getPubkey = {
- id: crypto.randomUUID(),
- method: "get_public_key",
- params: [],
- };
-
- let testEvent = {
- created_at: Math.round(Date.now() / 1000),
- kind: 1,
- content: "hi mom",
- tags: [],
- };
-
- let signEvent = {
- id: crypto.randomUUID(),
- method: "sign_event",
- params: [JSON.stringify(testEvent)],
- };
+ let nostrConnect = async () => {
+ let secret = crypto.randomUUID();
- let event = {
- created_at: Math.round(Date.now() / 1000),
- kind: 24133,
- pubkey,
- content: encrypt(JSON.stringify(signEvent), ck),
- tags: [["p", pk]],
- };
+ sk = generateSecretKey();
+ pubkey = getPublicKey(sk);
- let signedEvent = finalizeEvent(event, sk);
- await relay.publish(signedEvent);
- };
+ connectUrl = `nostrconnect://${pubkey}?relay=${encodeURIComponent(relayUrl)}&perms=sign_event%3A1&name=Coinos&secret=${secret}`;
- let nostrConnect = async () => {
- let secret = crypto.randomUUID();
- let sk = generateSecretKey();
- console.log("SK", bytesToHex(sk));
- let pubkey = getPublicKey(sk);
- console.log("PUBKEY", pubkey);
- connectUrl = `nostrconnect://${pubkey}?relay=wss%3A%2F%2Frelay.coinos.io&perms=nip44_encrypt%2Cnip44_decrypt%2Csign_event%3A13%2Csign_event%3A14%2Csign_event%3A1059&name=Coinos&secret=${secret}`;
+ let relay = await Relay.connect(relayUrl);
- const relay = await Relay.connect("wss://relay.coinos.io");
- console.log(`connected to ${relay.url}`);
- let finished, remoteSignerPubkey;
+ let signatureRequested;
const sub = relay.subscribe([{ kinds: [24133], "#p": [pubkey] }], {
async onevent(event) {
- console.log("got event:", event);
- remoteSignerPubkey = event.pubkey;
- // console.log("decrypted", decrypt(event.content, sk));
- if (!finished) {
- finished = true;
- let event = {
- created_at: Math.round(Date.now() / 1000),
- kind: 24133,
- pubkey,
- content: encrypt(
- JSON.stringify({
- id: "1234",
- method: "get_public_key",
- params: [],
- }),
- sk,
- hexToBytes(remoteSignerPubkey),
- ),
- tags: [["p", remoteSignerPubkey]],
+ pk = event.pubkey;
+ ck = getConversationKey(sk, pk);
+ let decrypted;
+ console.log("EVENT", event);
+ try {
+ decrypted = JSON.parse(decrypt(event.content, ck));
+ } catch (e) {
+ try {
+ decrypted = JSON.parse(await nip04.decrypt(sk, pk, event.content));
+ } catch (e) {
+ console.log("ERROR", e);
+ }
+ }
+
+ if (decrypted?.result?.includes("sig")) {
+ await nostrLogin(JSON.parse(decrypted.result));
+ } else if (!signatureRequested) {
+ signatureRequested = true;
+ let signEvent = {
+ id: crypto.randomUUID(),
+ method: "sign_event",
+ params: [JSON.stringify({ ...ev, pubkey })],
};
- console.log("asking for public key", event);
- console.log("DECRYPTED", decrypt(event.content, sk));
- let signedEvent = finalizeEvent(event, sk);
- console.log("sleeping");
- await new Promise((r) => setTimeout(r, 5000));
- console.log("sending");
- await relay.publish(signedEvent);
+ // let content = encrypt(JSON.stringify(signEvent), ck);
+ let content = await nip04.encrypt(sk, pk, JSON.stringify(signEvent));
+ console.log("CONTENT", content);
+ let signedSignEvent = finalizeEvent(
+ {
+ created_at: Math.round(Date.now() / 1000),
+ kind: 24133,
+ pubkey,
+ content,
+ tags: [["p", pk]],
+ },
+ sk,
+ );
+
+ await new Promise((r) => setTimeout(r, 1000));
+ console.log("PUBLISHING", signedSignEvent);
+ relay.publish(signedSignEvent);
}
},
});
- console.log("subbed");
};
- let pubkey = $state();
let ev = $derived({
kind: 1,
created_at: Date.now(),
@@ -200,14 +136,9 @@
ev.pubkey = pubkey;
console.log("PUBKEY", ev.pubkey);
};
- //
- // let signerSign = async () => {
- // const signer = new AmberClipboardSigner();
- // ev.sig = await signer.signEvent(ev);
- // nostrLogin(await signer.signEvent(ev));
- // };
- //
+ let signerSigning;
let signerSign = async () => {
+ signerSigning = true;
document.addEventListener("focus", signerSigned, true);
};
@@ -223,8 +154,6 @@
// let pubkey = await window.nostr.getPublicKey();
const formData = new FormData();
- console.log("SIGNED", signedEvent);
-
try {
formData.append("loginRedirect", redirect);
formData.append("token", token);
@@ -249,6 +178,8 @@
};
</script>
+hi
+{nostrSignin}
{#if nostrSignin}
<div
class="fixed inset-0 bg-base-100 bg-opacity-90 overflow-y-auto h-full w-full z-50"
@@ -260,10 +191,25 @@
{$t("login.nostr")}
</h1>
- <!-- <div class="break-all"> -->
- <!-- {JSON.stringify(ev)} -->
- <!-- </div> -->
- {#if pubkey}
+ {#if showNsec}
+ <input bind:value={nsec} placeholder="nsec..." />
+ <button type="button" class="btn" onclick={nsecSign}>
+ <iconify-icon icon="ph:key-bold" width="32"></iconify-icon>
+ <div class="my-auto">Login</div>
+ </button>
+ {:else if connectUrl}
+ <a href={connectUrl}>
+ <img
+ src={`/qr/${encodeURIComponent(connectUrl)}/raw`}
+ class="z-10 border-4 border-white"
+ alt="QR"
+ />
+ <div class="break-all">
+ {connectUrl}
+ </div>
+ </a>
+ <button class="btn" onclick={() => copy(connectUrl)}>Copy</button>
+ {:else if signerSigning && pubkey}
<a
href={`nostrsigner:${encodeURIComponent(JSON.stringify(ev))}?compressionType=none&returnType=signature&type=sign_event&appName=Coinos`}
type="button"
@@ -288,25 +234,10 @@
<div class="my-auto">NIP-10 Extension</div>
</button>
{/if}
- <!-- {#if connectUrl} -->
- <!-- <a href={connectUrl}> -->
- <!-- connect -->
- <!-- <img -->
- <!-- src={`/qr/${encodeURIComponent(connectUrl)}/raw`} -->
- <!-- class="z-10 border-4 border-white" -->
- <!-- alt="QR" -->
- <!-- /> -->
- <!-- <div class="break-all"> -->
- <!-- {connectUrl} -->
- <!-- </div> -->
- <!-- </a> -->
- <!-- <button class="btn" onclick={() => copy(connectUrl)}>Copy</button> -->
- <!-- {:else} -->
- <!-- <button type="button" class="btn" onclick={nostrConnect}> -->
- <!-- <img src="/images/nostr.png" class="w-8" /> -->
- <!-- <div class="my-auto">NIP-46 Connect</div> -->
- <!-- </button> -->
- <!-- {/if} -->
+ <button type="button" class="btn" onclick={nostrConnect}>
+ <img src="/images/nostr.png" class="w-8" />
+ <div class="my-auto">NIP-46 Connect</div>
+ </button>
{#if signer}
<a type="button" class="btn" onclick={signerGetPubkey}>
<iconify-icon
@@ -318,19 +249,16 @@
</a>
{/if}
- {#if showNsec}
- <input bind:value={nsec} placeholder="nsec..." />
- <button type="button" class="btn" onclick={nsecSign}>
- <iconify-icon icon="ph:key-bold" width="32"></iconify-icon>
- <div class="my-auto">Nsec login</div>
- </button>
- {:else}
- <button type="button" class="btn" onclick={toggleNsec}>
- <iconify-icon icon="ph:key-bold" width="32"></iconify-icon>
- <div class="my-auto">Nsec login</div>
- </button>
- {/if}
+ <button type="button" class="btn" onclick={toggleNsec}>
+ <iconify-icon icon="ph:key-bold" width="32"></iconify-icon>
+ <div class="my-auto">Nsec Login</div>
+ </button>
{/if}
+
+ <button type="button" class="btn" onclick={cancel}>
+ <iconify-icon icon="ph:x-bold" width="32"></iconify-icon>
+ <div class="my-auto">Cancel</div>
+ </button>
</div>
</div>
{/if}