This commit is contained in:
tsukino
2024-01-01 22:23:00 -08:00
parent 8f6732c64b
commit 21a55f6234
8 changed files with 151 additions and 50 deletions

View File

@@ -3,3 +3,4 @@ export { default as ECDH } from './ecdh';
export { default as AES } from './aes';
export { default as ZK } from './zk';
export { hexify, bufferify, strip0x, sha256 } from './utils/encoding';
export { generateMerkleTree } from '@zk-kit/protocols';

View File

@@ -75,6 +75,61 @@ export default class LevelDBAdapter
await this.#db.close();
}
async getStats(
type?: 'users' | 'posts' | 'moderations' | 'connections' | 'messages',
) {
console.time('level.getStats');
const stats: {
users?: number;
posts?: number;
moderations?: number;
connections?: number;
messages?: number;
} = {};
if (!type || type === 'users') {
stats.users = (await this.#getKeys(this.#indices.user)).length;
}
if (!type || type === 'moderations') {
stats.moderations = (
await this.#getKeys(
this.#indices.global.sublevel(MessageType[MessageType.Moderation], {
valueEncoding: 'json',
}),
)
).length;
}
if (!type || type === 'posts') {
stats.posts = (
await this.#getKeys(
this.#indices.global.sublevel(MessageType[MessageType.Post], {
valueEncoding: 'json',
}),
)
).length;
}
if (!type || type === 'connections') {
stats.connections = (
await this.#getKeys(
this.#indices.global.sublevel(MessageType[MessageType.Connection], {
valueEncoding: 'json',
}),
)
).length;
}
if (!type || type === 'messages') {
stats.messages = (await this.#getKeys(this.#db)).length;
}
console.timeEnd('level.getStats');
return stats;
}
async reindex() {
console.log('clearing indices');
await this.#indices.user.clear();
@@ -638,12 +693,13 @@ export default class LevelDBAdapter
const mods = await this.getModerations(reference);
const threads = await this.getThreads(reference);
return {
const result = {
moderations: flattenByCreatorSubtype(mods),
threads: flattenByCreatorSubtype(threads),
moderated: reduceByCreatorSubtype(mods, own),
threaded: reduceByCreatorSubtype(threads, own),
};
return result;
}
async getUserMeta(user: string): Promise<{
@@ -672,6 +728,17 @@ export default class LevelDBAdapter
return names;
}
async #getKeys(
db: Level<string, AnyJSON> | AbstractSublevel<any, any, any, any>,
) {
const keys = await db.keys();
const result = [];
for await (const key of keys) {
result.push(key);
}
return result;
}
async getMessage<MessageType = Any>(
hash: string,
): Promise<MessageType | null> {

View File

@@ -54,6 +54,8 @@ export class BaseNode extends EventEmitter2 {
this.emit('pubsub:message:success', message.json);
}
return;
} else if (message.proof.type === ProofType.Semaphore) {
console.log('wow');
}
} catch (e) {
this.emit(`pubsub:error`, e);

View File

@@ -13,6 +13,7 @@ import { Observable } from '../../../lib/state.ts';
import css from './index.scss';
import $editor from '../../state/editor.ts';
import XmarkIcon from '../../../static/icons/xmark.svg';
import { ECDSA } from '@crypto';
export default class Editor extends CustomElement {
css = css.toString();
@@ -21,12 +22,15 @@ export default class Editor extends CustomElement {
async subscribe() {
this.listen($editor.reference);
this.listen($signer.$ecdsa);
this.listen($signer.$identity);
this.listen(this.$content);
}
onSubmit = () => {
const creator = $signer.$ecdsa.$?.publicKey || '';
const creator =
$signer.$identity.$ instanceof ECDSA
? $signer.$identity.$.publicKey || ''
: '';
const content = this.$content.$;
const post = new Post({
@@ -59,12 +63,15 @@ export default class Editor extends CustomElement {
};
async update() {
this.updateSigner();
this.updateReference();
await this.updateSigner();
await this.updateReference();
}
async updateSigner() {
const creator = $signer.$ecdsa.$?.publicKey || '';
const creator =
$signer.$identity.$ instanceof ECDSA
? $signer.$identity.$.publicKey || ''
: '';
const name = userName(creator) || 'Anonymous';
const handle = userId(creator) || '';
this.query('profile-image')!.setAttribute('creator', creator);
@@ -75,13 +82,13 @@ export default class Editor extends CustomElement {
// @ts-ignore;
this.query('textarea.content')!.value = this.$content.$;
if (!$signer.$ecdsa.$?.privateKey) {
if (!$signer.$identity.$) {
this.query('textarea.content')!.setAttribute('disabled', 'true');
} else {
this.query('textarea.content')!.removeAttribute('disabled');
}
if (!this.$content.$ || !$signer.$ecdsa.$?.privateKey) {
if (!this.$content.$ || !$signer.$identity.$) {
this.query('c-button#submit')!.setAttribute('disabled', 'true');
} else {
this.query('c-button#submit')!.removeAttribute('disabled');
@@ -107,6 +114,7 @@ export default class Editor extends CustomElement {
this.query('span.ref__text.ref__text--reply')!.textContent =
`Replying to ${parentHandle}`;
}
render(): VNode {
return h(
'div.editor',
@@ -151,7 +159,7 @@ export default class Editor extends CustomElement {
rows: '6',
placeholder: 'Say something here',
oninput: this.onInput,
...disabled(!$signer.$ecdsa.$?.privateKey),
...disabled(!$signer.$identity.$),
}),
h(
'div.bottom',
@@ -160,7 +168,7 @@ export default class Editor extends CustomElement {
// @ts-ignore
{
onclick: this.onSubmit,
...disabled(!this.$content.$ || !$signer.$ecdsa.$?.privateKey),
...disabled(!this.$content.$ || !$signer.$identity.$),
},
'Submit',
),

View File

@@ -5,12 +5,13 @@ import '../Editor';
import { Post, PostSubtype, ProofType } from '@message';
import $node from '../../state/node.ts';
import $editor from '../../state/editor.ts';
import { ECDSA, ZK } from '@crypto';
export default class LeftSidebar extends CustomElement {
css = css.toString();
async subscribe(): Promise<void> {
this.listen($signer.$ecdsa);
this.listen($signer.$identity);
this.listen($editor.reference);
}
@@ -23,16 +24,28 @@ export default class LeftSidebar extends CustomElement {
reference: $editor.reference.$ || '',
});
if (p) {
if ($signer.$ecdsa.$?.privateKey) {
const identity = $signer.$identity.$;
console.log(p, identity);
if (p && identity) {
if (identity instanceof ECDSA) {
const signature = await identity.sign(p.hash);
p.commit({
type: ProofType.ECDSA,
value: $signer.$ecdsa.$.sign(p.hash),
value: signature,
});
await $node.node.publish(p);
reset();
} else if (identity instanceof ZK) {
// p.commit({
// type: ProofType.Semaphore,
// value: await identity.genSemaphoreProof({
// signal: p.hash,
// merkleProof: tree.createProof(0),
// }),
// });
}
await $node.node.publish(p);
reset();
}
};
@@ -49,7 +62,7 @@ export default class LeftSidebar extends CustomElement {
// @ts-ignore
{
onclick: () => {
$signer.generateRandomPrivateKey();
$signer.generateRandomZKIdentity();
},
},
'Generate Private Key',

View File

@@ -27,6 +27,7 @@ import {
RevertSubtype,
} from '@message';
import $signer from '../../state/signer.ts';
import { ECDSA } from '@crypto';
export default class PostCard extends CustomElement {
static get observedAttributes() {
@@ -36,7 +37,7 @@ export default class PostCard extends CustomElement {
css = css.toString();
async subscribe(): Promise<void> {
this.listen($signer.$ecdsa);
this.listen($signer.$identity);
if (!this.state.hash) return;
@@ -72,10 +73,7 @@ export default class PostCard extends CustomElement {
const p = $node.getPost(hash);
const u = $node.$users.get(p?.creator || '');
const rpu = $node.$users.get(repost?.creator || '');
const postmeta = $node.getPostMeta(
p?.messageId,
$signer.$ecdsa.$?.publicKey,
);
const postmeta = $node.getPostMeta(p?.messageId, $signer.publicKey);
const creator = p?.json.creator || '';
const createat = fromNow(p?.json.createdAt) || '';
@@ -142,7 +140,7 @@ export default class PostCard extends CustomElement {
this.query('c-button.comment-btn')!.removeAttribute('active');
}
if ($signer.$ecdsa.$?.privateKey) {
if ($signer.$identity.$) {
this.query('c-button.comment-btn')!.removeAttribute('disabled');
this.query('c-button.like-btn')!.removeAttribute('disabled');
this.query('c-button.repost-btn')!.removeAttribute('disabled');
@@ -183,11 +181,11 @@ export default class PostCard extends CustomElement {
if (!p.$?.messageId) return;
if (!$signer.$ecdsa.$ || !$signer.$ecdsa.$.publicKey) return;
if (!$signer.publicKey) return;
const postmeta = await $node.node.db.db.getPostMeta(
p.$.messageId,
$signer.$ecdsa.$.publicKey,
$signer.publicKey,
);
let msg;
@@ -197,7 +195,7 @@ export default class PostCard extends CustomElement {
type: MessageType.Revert,
subtype: RevertSubtype.Default,
reference: postmeta.threaded[PostSubtype.Repost],
creator: $signer.$ecdsa.$.publicKey,
creator: $signer.publicKey,
createdAt: new Date(),
});
} else {
@@ -205,17 +203,19 @@ export default class PostCard extends CustomElement {
type: MessageType.Post,
subtype: PostSubtype.Repost,
reference: p.$.messageId,
creator: $signer.$ecdsa.$.publicKey,
creator: $signer.publicKey,
createdAt: new Date(),
});
}
msg.commit({
type: ProofType.ECDSA,
value: $signer.$ecdsa.$.sign(msg.hash),
});
if ($signer.$identity.$ instanceof ECDSA) {
msg.commit({
type: ProofType.ECDSA,
value: $signer.$identity.$.sign(msg.hash),
});
return $node.node.publish(msg);
return $node.node.publish(msg);
}
};
toggleLike = async (evt: PointerEvent) => {
@@ -226,11 +226,11 @@ export default class PostCard extends CustomElement {
if (!p.$?.messageId) return;
if (!$signer.$ecdsa.$ || !$signer.$ecdsa.$.publicKey) return;
if (!$signer.publicKey) return;
const postmeta = await $node.node.db.db.getPostMeta(
p.$.messageId,
$signer.$ecdsa.$.publicKey,
$signer.publicKey,
);
let msg;
@@ -240,7 +240,7 @@ export default class PostCard extends CustomElement {
type: MessageType.Revert,
subtype: RevertSubtype.Default,
reference: postmeta.moderated[ModerationSubtype.Like],
creator: $signer.$ecdsa.$.publicKey,
creator: $signer.publicKey,
createdAt: new Date(),
});
} else {
@@ -248,17 +248,19 @@ export default class PostCard extends CustomElement {
type: MessageType.Moderation,
subtype: ModerationSubtype.Like,
reference: p.$.messageId,
creator: $signer.$ecdsa.$.publicKey,
creator: $signer.publicKey,
createdAt: new Date(),
});
}
msg.commit({
type: ProofType.ECDSA,
value: $signer.$ecdsa.$.sign(msg.hash),
});
if ($signer.$identity.$ instanceof ECDSA) {
msg.commit({
type: ProofType.ECDSA,
value: $signer.$identity.$.sign(msg.hash),
});
return $node.node.publish(msg);
return $node.node.publish(msg);
}
};
render() {
@@ -332,7 +334,7 @@ export default class PostCard extends CustomElement {
className: className,
title: title,
...boolAttr('active', active),
...disabled(!$signer.$ecdsa.$?.privateKey),
...disabled(!$signer.$identity.$),
onclick: onclick,
},
h('img', { src: props.src }),

View File

@@ -8,4 +8,5 @@ import PostView from './pages/PostView';
Router.add(/(.*?)/, new App());
console.log((await $node.node.db.db.getPosts()).length);
$node.waitForStart();
console.log(await $node.node.db.db.getStats());
})();

View File

@@ -1,15 +1,22 @@
import { Observable } from '../../lib/state.ts';
import { ECDSA } from '@crypto';
import { ECDSA, ZK } from '@crypto';
export class Signer {
$ecdsa: Observable<ECDSA | null> = new Observable<ECDSA | null>(null);
async generateRandomPrivateKey() {
this.$ecdsa.$ = new ECDSA();
}
$identity: Observable<ZK | ECDSA | null> = new Observable<ZK | ECDSA | null>(
null,
);
get publicKey() {
return this.$ecdsa.$?.publicKey || '';
if (this.$identity instanceof ECDSA) return this.$identity.publicKey;
return '';
}
async generateRandomPrivateKey() {
this.$identity.$ = new ECDSA();
}
async generateRandomZKIdentity() {
this.$identity.$ = new ZK();
}
}