aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/utils.js24
-rw-r--r--src/routes/(app)/[username]/+page.server.js9
-rw-r--r--src/routes/(app)/[username]/+page.svelte60
-rw-r--r--src/routes/(app)/[username]/+server.js6
-rw-r--r--src/routes/(app)/[username]/generate/+page.svelte27
5 files changed, 98 insertions, 28 deletions
diff --git a/src/lib/utils.js b/src/lib/utils.js
index f59b6359..14646ad0 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -1,3 +1,5 @@
+import * as ecc from 'tiny-secp256k1';
+import { BIP32Factory } from 'bip32';
import { browser } from '$app/environment';
import { toast } from '@zerodevx/svelte-toast';
import { goto } from '$app/navigation';
@@ -168,3 +170,25 @@ export const wait = async (f, s = 300) => {
if (i >= s) throw new Error('timeout');
return f();
};
+
+export const stretch = async (password, salt) =>
+ crypto.subtle.deriveKey(
+ {
+ name: 'PBKDF2',
+ salt,
+ iterations: 100000,
+ hash: 'SHA-256'
+ },
+ await crypto.subtle.importKey(
+ 'raw',
+ new TextEncoder().encode(password),
+ { name: 'PBKDF2' },
+ false,
+ ['deriveBits', 'deriveKey']
+ ),
+ { name: 'AES-GCM', length: 256 },
+ true,
+ ['encrypt', 'decrypt']
+ );
+
+export const bip32 = await BIP32Factory(ecc);
diff --git a/src/routes/(app)/[username]/+page.server.js b/src/routes/(app)/[username]/+page.server.js
index 01dfab5a..547f754f 100644
--- a/src/routes/(app)/[username]/+page.server.js
+++ b/src/routes/(app)/[username]/+page.server.js
@@ -1,14 +1,19 @@
import { get } from '$lib/utils';
import Qr from 'qrcode-base64';
-export async function load({ params, url }) {
+export async function load({ params, parent, url }) {
+ let { user } = await parent();
+ let pubkey;
+ if (user) ({ pubkey } = user);
+ else pubkey = params.username;
+
let { username } = params;
let text = `${encodeURI(username)}@${url.hostname}`;
let src = Qr.drawImg(text, { size: 300 });
let events = [];
try {
- events = await get(`/${username}/events`);
+ events = await get(`/${pubkey}/events`);
} catch (e) {
console.log(e);
}
diff --git a/src/routes/(app)/[username]/+page.svelte b/src/routes/(app)/[username]/+page.svelte
index 78d84653..837257ef 100644
--- a/src/routes/(app)/[username]/+page.svelte
+++ b/src/routes/(app)/[username]/+page.svelte
@@ -1,12 +1,53 @@
<script>
+ import { Buffer } from 'buffer';
+ import { entropyToMnemonic, mnemonicToSeedSync } from 'bip39';
+ import { enhance } from '$app/forms';
import { Feed, Icon, PageNotFound } from '$comp';
import { t } from '$lib/translations';
+ import { bech32m } from 'bech32';
+ import { calculateId, signId } from 'nostr';
+ import { bip32, stretch, post } from '$lib/utils';
+
+ const { decode, fromWords } = bech32m;
export let data;
+ let message;
+
let { events, user, subject, src, text } = data;
let followed = false;
let { username: n } = subject;
+
+ let submit = async () => {
+ let mnemonic, key, password, seed, entropy, child, privkey;
+ entropy = Buffer.from(
+ await crypto.subtle.decrypt(
+ { name: 'AES-GCM', iv: new Uint8Array(16) },
+ await stretch(password, Buffer.from(user.salt, 'hex')),
+ Uint8Array.from(fromWords(decode(user.cipher, 180).words))
+ ),
+ 'hex'
+ ).toString('hex');
+
+ mnemonic = entropyToMnemonic(entropy);
+ seed = mnemonicToSeedSync(mnemonic);
+ key = bip32.fromSeed(seed);
+ child = key.derivePath("m/44'/1237'/0'/0/0");
+ privkey = child.privateKey;
+
+ let event = {
+ pubkey: user.pubkey,
+ created_at: Math.floor(Date.now() / 1000),
+ kind: 1,
+ content: message,
+ tags: []
+ };
+
+ event.id = await calculateId(event);
+ event.sig = await signId(privkey, event.id);
+ await post(`/${user.username}`, { event });
+ };
+
$: username = n.length > 60 ? n.substr(0, 6) : n;
</script>
@@ -69,9 +110,24 @@
</div>
</div>
- <div class="w-full flex md:pt-12 lg:pt-0">
+ <div class="w-full md:pt-12 lg:pt-0">
+ {#if user.username === n}
+ <form on:submit|preventDefault={submit}>
+ <input
+ name="message"
+ bind:value={message}
+ placeholder="What's on your mind?"
+ class="w-full my-5 max-w-lg mx-auto"
+ />
+ </form>
+ {/if}
+
<div class="mx-auto space-y-5 mt-5 lg:max-w-lg xl:max-w-2xl">
- <Feed {events} />
+ {#if events.length}
+ <Feed {events} />
+ {:else}
+ <div class="text-center">You haven't posted anything yet</div>
+ {/if}
</div>
</div>
</div>
diff --git a/src/routes/(app)/[username]/+server.js b/src/routes/(app)/[username]/+server.js
new file mode 100644
index 00000000..d0b1242f
--- /dev/null
+++ b/src/routes/(app)/[username]/+server.js
@@ -0,0 +1,6 @@
+import { auth, post } from '$lib/utils';
+import { json } from '@sveltejs/kit';
+
+export async function POST({ cookies, request }) {
+ return json(post('/nostr/send', await request.json(), auth(cookies)));
+}
diff --git a/src/routes/(app)/[username]/generate/+page.svelte b/src/routes/(app)/[username]/generate/+page.svelte
index ee67237c..fd6b6f7e 100644
--- a/src/routes/(app)/[username]/generate/+page.svelte
+++ b/src/routes/(app)/[username]/generate/+page.svelte
@@ -1,42 +1,20 @@
<script>
import { Buffer } from 'buffer';
import { onMount } from 'svelte';
- import { BIP32Factory } from 'bip32';
import { bech32m } from 'bech32';
import { generateMnemonic, mnemonicToEntropy, mnemonicToSeedSync } from 'bip39';
import * as ecc from 'tiny-secp256k1';
- import { post } from '$lib/utils';
+ import { bip32, stretch, post } from '$lib/utils';
import { goto } from '$app/navigation';
export let data;
let { user } = data;
- const { encode, decode, fromWords, toWords } = bech32m;
-
- const stretch = async (password, salt) =>
- crypto.subtle.deriveKey(
- {
- name: 'PBKDF2',
- salt,
- iterations: 100000,
- hash: 'SHA-256'
- },
- await crypto.subtle.importKey(
- 'raw',
- new TextEncoder().encode(password),
- { name: 'PBKDF2' },
- false,
- ['deriveBits', 'deriveKey']
- ),
- { name: 'AES-GCM', length: 256 },
- true,
- ['encrypt', 'decrypt']
- );
+ const { encode, toWords } = bech32m;
let mnemonic, key, password, seed, entropy, cipher, pubkey, salt, child;
onMount(async () => {
- let bip32 = await BIP32Factory(ecc);
mnemonic = generateMnemonic();
seed = mnemonicToSeedSync(mnemonic);
entropy = mnemonicToEntropy(mnemonic);
@@ -54,6 +32,7 @@
user.pubkey = Buffer.from(ecc.xOnlyPointFromPoint(child.publicKey)).toString('hex');
user.cipher = encode('en', toWords(bytes), 180);
+ user.salt = Buffer.from(salt).toString('hex');
await post(`/${user.username}/generate`, user);
goto(`/${user.username}/dashboard`);