added support for nevent and nprofile at least partially ( no attempt to get them from relays)

This commit is contained in:
Vishal
2025-07-30 22:08:00 +05:30
parent a43e724673
commit 666031836e
4 changed files with 160 additions and 26 deletions

View File

@@ -349,28 +349,38 @@ class EventData {
if( !content.contains("nostr:") ) {
return content;
}
var localDebug = false;
if(localDebug) print("------->\n\n<------- content = \n$content\n\n\n");
//print("------------------\nin expandMentions: content = $content \n");
String replaceMentions(Match mentionTagMatch) {
//print("in replaceMentions\n");
if(localDebug) print("\n-------------------\nin replaceMentions");
String? mentionTag = mentionTagMatch.group(0);
if( mentionTag != null) {
//print("mentionTag = $mentionTag");
if(localDebug) print("mentionTag = $mentionTag");
String strBechId = mentionTag.substring(6, mentionTag.length);
String tempType = strBechId.substring(0, 4);
if( tempType != "note" && tempType != "npub") {
//String tempType = strBechId.substring(0, 4);
if( !strBechId.startsWith((RegExp(r'npub|note|nevent|nprofile')))) {
if(localDebug) print('returning from replaceMentions');
return "nostr:$strBechId";
}
//print("Going to decode: $strBechId");
try {
Map<String, String> nsec = bech32Decode(strBechId);
String? type = nsec["prefix"]; // type can be "note" or "npub"
String? strHex = nsec["data"]; // this is 64 byte hex pubkey or note id
if( strHex != null && type != null) {
String mentionedId = strHex;
//print("strHex = $strHex type = $type");
if( type == "npub") {
if(localDebug) print("Going to decode: $strBechId");
try {
Map<String, String> bech32str = bech32Decode(strBechId);
if(localDebug) print('after bech32Decode');
String? type = bech32str["prefix"]; // type can be "note", "npub", nevent, nprofile ( others not supported yet)
String? hexData = bech32str["data"]; // the data for given type
if(localDebug) print('after bech32Decode 2');
if( hexData != null && type != null) {
String mentionedId = hexData;
if(localDebug) print("strHex = $hexData type = $type");
switch(type) {
case "npub":
if( gKindONames.containsKey(mentionedId)) {
String? author = getOnlyAuthorName(mentionedId);
@@ -381,7 +391,9 @@ class EventData {
return "@$author";
}
}
} else {
break;
case "note":
if( type == "note") {
EventData? mentionedEventData = tempChildEventsMap[mentionedId]?.event.eventData;
if( mentionedEventData != null) {
@@ -391,37 +403,91 @@ class EventData {
String mentionedContent = mentionedEventData.content;
if( mentionedEventData.evaluatedContent != "") {
//print("found evaluated content");
if(localDebug) print("found evaluated content");
mentionedContent = mentionedEventData.evaluatedContent;
} else {
//print("didnt find evaluated content");
if(localDebug) print("didnt find evaluated content");
}
String quote = "<Quoted event id '$prefixId' by $quotedAuthor: \"$mentionedContent\">";
//print("evaluatedContent: ${mentionedEventData.evaluatedContent}\n");
return quote;
}
}
break;
case "nevent":
if(localDebug) print("in nevent");
if(localDebug) print("nevent = $mentionedId");
Nevent nevent = Nip19.decodeNevent(mentionedId);
if( nevent["id"] != null) {
String id = nevent["id"] as String;
EventData? mentionedEventData = tempChildEventsMap[id]?.event.eventData;
if( mentionedEventData != null) {
String quotedAuthor = getAuthorName(mentionedEventData.pubkey);
String prefixId = mentionedId.substring(0, 3);
String mentionedContent = mentionedEventData.content;
if( mentionedEventData.evaluatedContent != "") {
if(localDebug) print("found evaluated content");
mentionedContent = mentionedEventData.evaluatedContent;
} else {
//print("Could not find event!\n");
if(localDebug) print("didnt find evaluated content");
}
String quote = "<Quoted event id '$prefixId' by $quotedAuthor: \"$mentionedContent\">";
//print("evaluatedContent: ${mentionedEventData.evaluatedContent}\n");
//print(quote);
return quote;
}
}
break;
case "nprofile":
if(localDebug) print("in nprofile");
if(localDebug) print("nprofile = $mentionedId");
Nevent nevent = Nip19.decodeNevent(mentionedId);
// id is pubkey here
if( nevent["id"] != null) {
String pubkey = nevent["id"] as String;
String? author = getOnlyAuthorName(pubkey);
if( author == null) {
if(localDebug) print("Could not find author for pubkey $pubkey");
return "nostr:$strBechId";
} else {
//print("Could not parse the given nsec/private key. Exiting.");
//print("Found author: $author");
return "@$author";
}
}
break;
default:
print("in default");
break;
}
return "nostr:$strBechId";
} else {
print("Could not parse the given nsec/private key. Exiting.");
return mentionTag;
}
} on Exception {
//print("====================Caught exctption.");
} on Exception catch (e) {
print("====================Caught exctption $e");
return "nostr:$strBechId";
}
}
if( gDebug >= 0) printWarning("In replaceMentions returning nothing");
printWarning("In replaceMentions returning nothing");
return "";
} // end replaceMentions()
// replace the mentions, if any are found
// The Bech32 alphabet contains 32 characters, including lowercase letters a-z and the numbers 0-9, excluding the number 1 and the letters b, i, o to avoid reader confusion.
String mentionStr = "(nostr:(npub1|note1)[a0c-hj-np-z2-9]{58})"; // bech32
String mentionStr = "(nostr:(npub1|note1)[a0c-hj-np-z2-9]{58})|(nostr:(nevent1|nprofile1)[a0c-hj-np-z2-9]+)"; // bech32
RegExp mentionRegExp = RegExp(mentionStr, caseSensitive: false);
content = content.replaceAllMapped(mentionRegExp, replaceMentions);
return content;

View File

@@ -1,6 +1,11 @@
import 'dart:convert';
import 'package:bech32/bech32.dart';
import 'package:convert/convert.dart';
// can have keys: id, relays ( whose value is an array of strings)
typedef Nevent = Map<String, Object>;
/// bech32-encoded entities
class Nip19 {
static encodePubkey(String pubkey) {
@@ -41,8 +46,68 @@ class Nip19 {
return "";
}
}
static Nevent decodeNevent(String data) {
var localDebug = false;
if(localDebug) print("in decodeNevent len data = ${data.length} data = $data");
Nevent nevent = {};
int iData = 0;
while( iData + 4 < data.length) {
if(localDebug) print("iData = $iData");
List<int> typeList = hex.decode( data.substring(iData, iData + 2));
List<int> lenList = hex.decode( data.substring(iData + 2, iData + 4));
int type = typeList[0];
int len = lenList[0];
if(localDebug) print("type = $type len = $len");
switch(type) {
case 0:
String id = data.substring(iData + 4, iData + 4 + len * 2);
nevent["id"] = id;
if(localDebug) print("nevent id = $id");
break;
case 1:
String relay = data.substring(iData + 4, iData + 4 + len * 2);
// convert hex string to list of int
List<int> intRelay = [];
intRelay = hex.decode(relay);
const asciiDecoder = AsciiDecoder(allowInvalid: true);
if(localDebug) print("before AsciiDecoder call");
final relayURL = asciiDecoder.convert(intRelay);
if( nevent["relays"] == null) {
nevent["relays"] = [relayURL];
} else {
(nevent["relays"] as List<String>).add(relayURL);
}
if(localDebug) print("nevent relay = $relayURL");
break;
case 2:
break;
case 3:
break;
default:
if(localDebug) print("in decodeNevent: malformed nevent" );
return nevent;
}
if(localDebug) print(" to next TLV");
iData = iData + 4 + len * 2 ;
}
return nevent;
}
}
/// help functions
String bech32Encode(String prefix, String hexData) {
@@ -53,7 +118,9 @@ String bech32Encode(String prefix, String hexData) {
}
Map<String, String> bech32Decode(String bech32Data) {
final decodedData = bech32.decode(bech32Data);
//print("in becn32Decode 1 bech32Data = $bech32Data");
final decodedData = bech32.decode(bech32Data, Bech32Validations.maxInputLength + 300);
//print(decodedData.hrp);
final convertedData = convertBits(decodedData.data, 5, 8, false);
final hexData = hex.encode(convertedData);

View File

@@ -1735,7 +1735,9 @@ class Store {
List<int> ret = [0,0,0];
//print("in printStoreTrees");
for( int i = 0; i < topPosts.length; i++) {
//print("i = $i");
// continue if this children isn't going to get printed anyway; selector is only called for top most tree
if( treeSelector(topPosts[i]) == false) {
continue;

View File

@@ -1,6 +1,5 @@
import 'dart:io';
import 'package:qr/qr.dart';
import 'package:nostr_console/nip_019.dart';
enum enumRoomType { kind4, kind40, kind140, RoomLocationTag, RoomTTag}