save latest decrypted dm content

This commit is contained in:
Martti Malmi 2023-08-04 13:10:46 +03:00
parent 666d18dfa5
commit 7594c08018
3 changed files with 58 additions and 12 deletions

View File

@ -17,7 +17,7 @@ localForage.config({
/**
Our very own implementation of the Gun (https://github.com/amark/gun) API. Used for local state management.
*/
class Node {
export class Node {
id: string;
parent: Node | null;
children = new Map<string, Node>();

View File

@ -4,7 +4,9 @@ import {
Event,
Filter,
getEventHash,
getPublicKey,
matchFilter,
nip04,
validateEvent,
verifySignature,
} from 'nostr-tools';
@ -12,7 +14,9 @@ import { EventTemplate } from 'nostr-tools';
import FuzzySearch from '../FuzzySearch';
import localState from '../LocalState';
import { Node } from '../LocalState';
import SortedMap from '../utils/SortedMap';
import { DecryptedEvent } from '../views/chat/ChatMessages';
import { addGroup, setGroupNameByInvite } from '../views/chat/NewChat';
import EventMetaStore from './EventsMeta';
@ -377,14 +381,14 @@ const Events = {
}
this.zapsByNote.get(zappedNote)?.add(event);
},
async saveDMToLocalState(event: Event, chatId: string) {
const latest = localState.get('chats').get(chatId).get('latest');
async saveDMToLocalState(event: DecryptedEvent, chatNode: Node) {
const latest = chatNode.get('latest');
const e = await latest.once();
if (!e || !e.created_at || e.created_at < event.created_at) {
latest.put({ id: event.id, created_at: event.created_at, text: '' });
latest.put({ id: event.id, created_at: event.created_at, text: event.text });
}
},
async handleDirectMessage(event: Event) {
async handleDirectMessage(event: DecryptedEvent) {
const myPub = Key.getPubKey();
let chatId;
let maybeSecretChat = false;
@ -405,23 +409,26 @@ const Events = {
try {
// TODO decrypting & trying to json parse all dms might be slow, how to avoid? only process new msgs?
const decrypted = await Key.decrypt(event.content, event.pubkey);
decrypted && this.decryptedMessages.set(event.id, decrypted); // don't do if maybeSecretChat?
if (decrypted) {
event.text = decrypted;
this.decryptedMessages.set(event.id, decrypted); // don't do if maybeSecretChat?
}
// also save to localState, so we don't have to decrypt every time?
const innerEvent = JSON.parse(decrypted.slice(decrypted.indexOf('{')));
if (validateEvent(innerEvent) && verifySignature(innerEvent)) {
console.log('innerEvent', innerEvent);
// parse nsec from message by regex. nsec is bech32 encoded in the message
// no follow distance check here for now
const nsec = innerEvent.content.match(/nsec1[023456789acdefghjklmnpqrstuvwxyz]{6,}/gi)?.[0];
if (nsec) {
const hexPriv = Key.toNostrHexAddress(nsec);
if (hexPriv) {
console.log('nsec & hexpriv');
// TODO browser notification?
addGroup(hexPriv, false, innerEvent.pubkey);
addGroup(hexPriv, false, innerEvent.pubkey); // for some reason, groups don't appear on 1st load after login
setGroupNameByInvite(hexPriv, innerEvent.pubkey);
localState.get('chatInvites').get(innerEvent.pubkey).put({ priv: hexPriv });
if (maybeSecretChat) {
return;
}
return;
}
}
}
@ -442,9 +449,45 @@ const Events = {
this.insert(event);
if (!maybeSecretChat) {
this.saveDMToLocalState(event, chatId);
this.saveDMToLocalState(event, localState.get('chats').get(chatId));
}
},
getEventFromText(text) {
try {
const maybeJson = text.slice(text.indexOf('{'));
console.log('maybeJson', maybeJson);
const e = JSON.parse(maybeJson);
if (validateEvent(e) && verifySignature(e)) {
return e;
}
} catch (e) {
// ignore
}
},
subscribeGroups() {
localState.get('groups').map((data, groupId) => {
if (data.key) {
const pubKey = getPublicKey(data.key);
if (pubKey) {
console.log('subscribing to group', groupId, pubKey);
PubSub.subscribe({ authors: [pubKey], kinds: [4], '#p': [pubKey] }, async (event) => {
const decrypted = await nip04.decrypt(data.key, pubKey, event.content);
const innerEvent = this.getEventFromText(decrypted);
if (
innerEvent &&
innerEvent.tags.length === 1 &&
innerEvent.tags[0][0] === 'p' &&
innerEvent.tags[0][1] === pubKey
) {
innerEvent.text = innerEvent.content;
console.log('saving innerEvent', innerEvent);
this.saveDMToLocalState(innerEvent, localState.get('groups').get(groupId));
}
});
}
}
});
},
handleKeyValue(event: Event) {
if (event.pubkey !== Key.getPubKey()) {
return;

View File

@ -133,7 +133,9 @@ const Session = {
});
setTimeout(() => {
PubSub.subscribe({ authors: [myPub] }, undefined, true); // our stuff
PubSub.subscribe({ '#p': [myPub], kinds: [1, 3, 4, 6, 7, 9735] }, undefined, true); // mentions, reactions, DMs
PubSub.subscribe({ '#p': [myPub], kinds: [1, 3, 6, 7, 9735] }, undefined, true); // mentions, reactions, DMs
PubSub.subscribe({ '#p': [myPub], kinds: [4] }, undefined, false); // comments, likes
PubSub.subscribe({ authors: [myPub], kinds: [4] }, undefined, false); // comments, likes
}, 200);
setInterval(() => {
console.log('handled msgs per second', Math.round(Events.handledMsgsPerSecond / 5));
@ -144,6 +146,7 @@ const Session = {
Key.getOrCreate(options);
localState.get('loggedIn').on(() => this.onLoggedIn());
localState.get('loggedIn').on(() => this.onLoggedIn());
Events.subscribeGroups();
},
};