From 3403bf5c6090109725493b4c7a4fef28266beda8 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 15 Feb 2023 19:57:47 -0800 Subject: messages on dashboard --- src/lib/nostr.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/lib/nostr.js') diff --git a/src/lib/nostr.js b/src/lib/nostr.js index de19b477..13251856 100644 --- a/src/lib/nostr.js +++ b/src/lib/nostr.js @@ -80,7 +80,7 @@ export let decrypt = async ({ event, user }) => { return Buffer.from(message).toString('utf8'); } catch (e) { - console.log(e); + // console.log(e); } }; @@ -119,6 +119,7 @@ let getPrivateKey = async (user) => { seed = mnemonicToSeedSync(mnemonic); key = bip32.fromSeed(seed); child = key.derivePath("m/44'/1237'/0'/0/0"); + return child.privateKey; }; -- cgit v1.2.3 From a97c7a00ebb414b7ff7731e6bf3640f2f476aae3 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 16 Feb 2023 22:43:27 -0800 Subject: messages --- package.json | 1 + pnpm-lock.yaml | 11 ++ src/components/About.svelte | 13 --- src/lib/nostr.js | 11 +- src/lib/socket.js | 27 +---- src/lib/store.js | 3 +- src/locales/en.json | 13 +-- src/routes/(app)/+layout.svelte | 2 +- .../(app)/[username]/(profile)/+layout.svelte | 2 +- .../(app)/[username]/(profile)/+page.server.js | 1 + src/routes/(app)/[username]/(profile)/+page.svelte | 80 +++++++------ .../[username]/(profile)/messages/+page.server.js | 16 --- .../[username]/(profile)/messages/+page.svelte | 123 -------------------- .../(app)/[username]/invoice/[hash]/+page.svelte | 4 +- .../(app)/[username]/messages/+page.server.js | 19 ++++ src/routes/(app)/[username]/messages/+page.svelte | 126 +++++++++++++++++++++ .../[username]/payments/[...page]/+page.svelte | 2 +- src/routes/(app)/buy/+page.svelte | 33 +++++- src/routes/(app)/login/+page.svelte | 1 - src/routes/(app)/payment/[id]/+page.svelte | 16 +-- tailwind.config.cjs | 3 +- 21 files changed, 261 insertions(+), 246 deletions(-) delete mode 100644 src/routes/(app)/[username]/(profile)/messages/+page.server.js delete mode 100644 src/routes/(app)/[username]/(profile)/messages/+page.svelte create mode 100644 src/routes/(app)/[username]/messages/+page.server.js create mode 100644 src/routes/(app)/[username]/messages/+page.svelte (limited to 'src/lib/nostr.js') diff --git a/package.json b/package.json index 908ec0bf..ac67d8b3 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "svelte-preprocess": "^4.10.7", "svelte-virtual-scroll-list": "^1.1.0", "sveltekit-i18n": "^2.2.2", + "tailwind-scrollbar": "^2.1.0", "tailwindcss": "^3.2.4", "tiny-secp256k1": "^2.2.1", "uuid": "^9.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f0d2ef2..3fe87f18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,7 @@ specifiers: svelte-preprocess: ^4.10.7 svelte-virtual-scroll-list: ^1.1.0 sveltekit-i18n: ^2.2.2 + tailwind-scrollbar: ^2.1.0 tailwindcss: ^3.2.4 tiny-secp256k1: ^2.2.1 uuid: ^9.0.0 @@ -68,6 +69,7 @@ devDependencies: svelte-preprocess: 4.10.7_qs7rgzvahok4cbkjoy5bgypde4 svelte-virtual-scroll-list: 1.1.0_svelte@3.55.0 sveltekit-i18n: 2.2.2_svelte@3.55.0 + tailwind-scrollbar: 2.1.0_tailwindcss@3.2.4 tailwindcss: 3.2.4_postcss@8.4.20 tiny-secp256k1: 2.2.1 uuid: 9.0.0 @@ -2477,6 +2479,15 @@ packages: svelte: 3.55.0 dev: true + /tailwind-scrollbar/2.1.0_tailwindcss@3.2.4: + resolution: {integrity: sha512-zpvY5mDs0130YzYjZKBiDaw32rygxk5RyJ4KmeHjGnwkvbjm/PszON1m4Bbt2DkMRIXlXsfNevykAESgURN4KA==} + engines: {node: '>=12.13.0'} + peerDependencies: + tailwindcss: 3.x + dependencies: + tailwindcss: 3.2.4_postcss@8.4.20 + dev: true + /tailwindcss/3.2.4_postcss@8.4.20: resolution: {integrity: sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==} engines: {node: '>=12.13.0'} diff --git a/src/components/About.svelte b/src/components/About.svelte index d51b9268..0a0ff874 100644 --- a/src/components/About.svelte +++ b/src/components/About.svelte @@ -17,19 +17,6 @@ name: 'john', socials: [] }, - { - name: 'karnage', - socials: [ - { type: 'twitter', url: 'https://twitter.com/KarnageBitcoin', color: 'bg-[#1D9BF0]' } - ] - }, - { - name: 'secondl1ght', - socials: [ - { type: 'twitter', url: 'https://www.twitter.com/secondl1ght', color: 'bg-[#1D9BF0]' }, - { type: 'github', url: 'https://github.com/secondl1ght', color: 'bg-gray-800' } - ] - }, { name: 'shauna', socials: [ diff --git a/src/lib/nostr.js b/src/lib/nostr.js index 13251856..d72f48ef 100644 --- a/src/lib/nostr.js +++ b/src/lib/nostr.js @@ -5,7 +5,7 @@ import { Buffer } from 'buffer'; import { bech32m } from 'bech32'; import { bip32, fail, wait, post, stretch } from '$lib/utils'; import { calculateId, signId } from 'nostr'; -import { password as pw, passwordPrompt, pin, loginRedirect } from '$lib/store'; +import { decrypted, password as pw, passwordPrompt, pin, loginRedirect } from '$lib/store'; import { goto, invalidate } from '$app/navigation'; const { encode, decode, fromWords, toWords } = bech32m; @@ -58,8 +58,10 @@ export let encrypt = async ({ message, recipient, user }) => { }; export let decrypt = async ({ event, user }) => { + let cache = get(decrypted); try { - let { content, pubkey } = event; + let { content, pubkey, id } = event; + if (cache[id]) return cache[id]; if (pubkey === user.pubkey) pubkey = event.tags[0][1]; pubkey = Uint8Array.from(Buffer.from('02' + pubkey, 'hex')); @@ -78,7 +80,10 @@ export let decrypt = async ({ event, user }) => { let message = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, key, cipher); - return Buffer.from(message).toString('utf8'); + cache[id] = Buffer.from(message).toString('utf8'); + decrypted.set(cache); + + return cache[id]; } catch (e) { // console.log(e); } diff --git a/src/lib/socket.js b/src/lib/socket.js index ce3cbe4b..aef8a513 100644 --- a/src/lib/socket.js +++ b/src/lib/socket.js @@ -1,23 +1,11 @@ import { get } from 'svelte/store'; -import { - events as $events, - invoice, - request, - newPayment, - last, - rate, - payments, - user -} from '$lib/store'; +import { event, invoice, request, newPayment, last, rate, payments, user } from '$lib/store'; import { success, sat } from '$lib/utils'; import { PUBLIC_SOCKET } from '$env/static/public'; import { invalidate } from '$app/navigation'; import { browser } from '$app/environment'; let socket, token; -let le = browser && localStorage.getItem('events'); -let events = le && le !== 'undefined' ? JSON.parse(le) : {}; -let q = Object.keys(events); export const auth = () => token && send('login', token) && send('heartbeat'); @@ -30,23 +18,12 @@ export const messages = (data) => ({ id() { last.set(Date.now()); }, - invoice() { invoice.set(data); }, - event() { - data.seen = Math.round(Date.now() / 1000); - events[data.id] = data; - q.push(data.id); - $events.set(events); - while (q.length > 10000) delete events[q.shift()]; - localStorage.setItem( - 'events', - JSON.stringify(q.slice(-100).reduce((a, b) => (a = { ...a, [b]: events[b] }), {})) - ); + event.set(data); }, - rate() { rate.set(data); }, diff --git a/src/lib/store.js b/src/lib/store.js index 93ac3d47..6853386c 100644 --- a/src/lib/store.js +++ b/src/lib/store.js @@ -36,11 +36,12 @@ export const animatedRate = writable(0); export const avatar = writable(); export const banner = writable(); export const colorTheme = writable('from-primary to-gradient'); +export const event = writable(); export const events = writable({}); export const invoice = writable(); export const last = writable(); export const loginRedirect = writable(); -export const messages = persistLocal('messages', {}); +export const decrypted = persistLocal('decrypted', {}); export const newPayment = persistLocal('newPayment'); export const password = persistLocal('password'); export const passwordPrompt = writable(); diff --git a/src/locales/en.json b/src/locales/en.json index 17f4b34e..402f0214 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -15,17 +15,6 @@ "position": "Chief Technical Officer", "bio": "Adam is a web developer and bitcoin enthusiast who believes sound money is key to increasing global prosperity. He lives in North Vancouver with his wife Chelsea and two children." }, - "secondl1ght": { - "name": "secondl1ght", - "position": "Web Developer", - "bio": "A self-taught Web Developer, secondl1ght dove head first down the bitcoin rabbit hole and left his fiat job to focus on bitcoin development full-time. He contributes to open source projects, is a privacy advocate, and freedom lover." - }, - - "karnage": { - "name": "Karnage", - "position": "Product Designer", - "bio": "My mission is to help startup founders succeed. I create products to achieve this goal. Pixel-perfect product design. Get it shipped." - }, "shauna": { "name": "Shauna", "position": "Operations & Marketing", @@ -297,6 +286,6 @@ "redeem": "Redeem", "redeemed": "Redeemed", "redeemedBy": "Redeemed by", - "sendMessage": "Message" + "sendMessage": "Write a message..." } } diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 2a122209..45469bdb 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -58,7 +58,7 @@ onDestroy(() => browser && clearTimeout(timer)); -{#if $passwordPrompt} +{#if browser && $passwordPrompt} {/if} diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte index dfa25b78..6eb2a850 100644 --- a/src/routes/(app)/[username]/(profile)/+layout.svelte +++ b/src/routes/(app)/[username]/(profile)/+layout.svelte @@ -111,7 +111,7 @@ {/if}
- + - - - - - - - - + {#if user.eligible} + + + + {/if}
{/if} @@ -138,17 +146,23 @@ {/if} - {#if latest.length} -
-

Messages

- {#each latest as { content, user }} -
-
- + {#if latest.length && user.id === subject.id} +
+ {#each latest as { content, pubkey, author, recipient }} + {@const user = author.id === user.id ? recipient : author} + +
+
+ +
+
+
{user.username}
+
+ {content} +
+
-
{user.username}
- {content} -
+ {/each}
{/if} diff --git a/src/routes/(app)/[username]/(profile)/messages/+page.server.js b/src/routes/(app)/[username]/(profile)/messages/+page.server.js deleted file mode 100644 index 63116099..00000000 --- a/src/routes/(app)/[username]/(profile)/messages/+page.server.js +++ /dev/null @@ -1,16 +0,0 @@ -import { get } from '$lib/utils'; - -export async function load({ params, parent, url }) { - let { user, subject } = await parent(); - let { since = 0 } = params; - - let messages = []; - - try { - messages = await get(`/nostr/${user.pubkey}/${subject.pubkey}/${since}/messages`); - } catch (e) { - console.log(`failed to fetch nostr messages`, e); - } - - return { newMessages: messages }; -} diff --git a/src/routes/(app)/[username]/(profile)/messages/+page.svelte b/src/routes/(app)/[username]/(profile)/messages/+page.svelte deleted file mode 100644 index db7b1ced..00000000 --- a/src/routes/(app)/[username]/(profile)/messages/+page.svelte +++ /dev/null @@ -1,123 +0,0 @@ - - -
-

- {$t('payments.sendMessage')} -

- -
- {#each events as data} - {@const ours = data.pubkey === user.pubkey} - {@const theirs = !ours} -
- {#if data.message} - {data.message} - {:else} - - - {/if} -
-
- {format(new Date(data.created_at * 1000), 'MMM d')}, - {format(new Date(data.created_at * 1000), 'h:mm aa')} -
- {/each} -
- -
- - - - -
-
- - diff --git a/src/routes/(app)/[username]/invoice/[hash]/+page.svelte b/src/routes/(app)/[username]/invoice/[hash]/+page.svelte index b5571f23..2ff92687 100644 --- a/src/routes/(app)/[username]/invoice/[hash]/+page.svelte +++ b/src/routes/(app)/[username]/invoice/[hash]/+page.svelte @@ -152,9 +152,9 @@ {/if}
- {txt.substr(0, 10)}...{txt.substr(-10)}
diff --git a/src/routes/(app)/[username]/messages/+page.server.js b/src/routes/(app)/[username]/messages/+page.server.js new file mode 100644 index 00000000..7b651389 --- /dev/null +++ b/src/routes/(app)/[username]/messages/+page.server.js @@ -0,0 +1,19 @@ +import { get } from '$lib/utils'; + +export async function load({ params, parent, url }) { + let { user, subject } = await parent(); + let { since = 0 } = params; + + let messages = []; + + try { + messages = await get(`/${user.pubkey}/${since}/messages`); + messages = messages + .filter((m) => m.recipient.id === subject.id || m.author.id === subject.id) + .sort((a, b) => a.created_at - b.created_at); + } catch (e) { + console.log(`failed to fetch nostr messages`, e); + } + + return { messages, user }; +} diff --git a/src/routes/(app)/[username]/messages/+page.svelte b/src/routes/(app)/[username]/messages/+page.svelte new file mode 100644 index 00000000..f8f64aea --- /dev/null +++ b/src/routes/(app)/[username]/messages/+page.svelte @@ -0,0 +1,126 @@ + + +
+ {#if messages.length && ready} +
+ {#each messages as event} + {@const ours = event.pubkey === user.pubkey} + {@const theirs = !ours} +
+
+ {#await decrypt({ event, user })} + - + {:then message} + {message} + {/await} +
+
+ +
+
+
+ {format(new Date(event.created_at * 1000), 'MMM d')}, + {format(new Date(event.created_at * 1000), 'h:mm aa')} +
+ {/each} +
+ {/if} + +
+ + + + +
+
+ + diff --git a/src/routes/(app)/[username]/payments/[...page]/+page.svelte b/src/routes/(app)/[username]/payments/[...page]/+page.svelte index 2068c306..aacba81e 100644 --- a/src/routes/(app)/[username]/payments/[...page]/+page.svelte +++ b/src/routes/(app)/[username]/payments/[...page]/+page.svelte @@ -182,7 +182,7 @@ {:else if p.with}
- +
{p.with.username}
diff --git a/src/routes/(app)/buy/+page.svelte b/src/routes/(app)/buy/+page.svelte index 323d5ef0..2f556ada 100644 --- a/src/routes/(app)/buy/+page.svelte +++ b/src/routes/(app)/buy/+page.svelte @@ -1,13 +1,33 @@
@@ -114,6 +134,17 @@
+ +
+
+
+
1
+ Bitcoin +
+
= {f($animatedRate, currency)}
+
+

3% credit card fee applies

+
diff --git a/src/routes/(app)/login/+page.svelte b/src/routes/(app)/login/+page.svelte index 9a1e41da..75998cd0 100644 --- a/src/routes/(app)/login/+page.svelte +++ b/src/routes/(app)/login/+page.svelte @@ -1,5 +1,4 @@