mirror of
https://github.com/hoytech/strfry.git
synced 2025-06-19 17:37:43 +00:00
nevent/nprofile
This commit is contained in:
@ -41,7 +41,7 @@ inline std::string encodeBech32Simple(const std::string &hrp, std::string_view v
|
||||
return bech32::encode(hrp, values5, bech32::Encoding::BECH32);
|
||||
}
|
||||
|
||||
inline std::string decodeBech32Simple(std::string_view v) {
|
||||
inline std::string decodeBech32Raw(std::string_view v) {
|
||||
auto res = bech32::decode(std::string(v));
|
||||
|
||||
if (res.encoding == bech32::Encoding::INVALID) throw herr("invalid bech32");
|
||||
@ -49,7 +49,43 @@ inline std::string decodeBech32Simple(std::string_view v) {
|
||||
|
||||
std::vector<uint8_t> out;
|
||||
if (!convertbits<5, 8, false>(out, res.data)) throw herr("convertbits failed");
|
||||
if (out.size() != 32) throw herr("unexpected size from bech32");
|
||||
|
||||
return std::string((char*)out.data(), out.size());
|
||||
}
|
||||
|
||||
inline std::string decodeBech32Simple(std::string_view v) {
|
||||
auto out = decodeBech32Raw(v);
|
||||
if (out.size() != 32) throw herr("unexpected size from bech32");
|
||||
return out;
|
||||
}
|
||||
|
||||
inline uint8_t getByte(std::string_view &encoded) {
|
||||
if (encoded.size() < 1) throw herr("parse ends prematurely");
|
||||
uint8_t output = encoded[0];
|
||||
encoded = encoded.substr(1);
|
||||
return output;
|
||||
}
|
||||
|
||||
inline std::string getBytes(std::string_view &encoded, size_t n) {
|
||||
if (encoded.size() < n) throw herr("parse ends prematurely");
|
||||
auto res = encoded.substr(0, n);
|
||||
encoded = encoded.substr(n);
|
||||
return std::string(res);
|
||||
};
|
||||
|
||||
inline std::string decodeBech32GetSpecial(std::string_view origStr) {
|
||||
auto decoded = decodeBech32Raw(origStr);
|
||||
std::string_view s(decoded);
|
||||
|
||||
while (s.size()) {
|
||||
auto tag = getByte(s);
|
||||
auto len = getByte(s);
|
||||
auto val = getBytes(s, len);
|
||||
if (tag == 0) {
|
||||
if (len != 32) throw herr("unexpected size from bech32 special");
|
||||
return std::string(val);
|
||||
}
|
||||
}
|
||||
|
||||
throw herr("no special tag found");
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
read
|
||||
* support nprofile/nevent/etc links
|
||||
example nevent: https://oddbean.com/e/note1qmye0at28we63aze93xjr92nzw725td0a5ncz3htwlc3wg78kp6q7802ad
|
||||
example nprofile: https://oddbean.com/e/note1ykjalrpaj6jvxeuc434yd7ksrj8yd2vte478700ta8np250l3clsyjvh4q
|
||||
* non-500 error pages when bech32 fails to parse, for example
|
||||
* search field: enter anything, pubkey (hex or npub), eventId, etc. maybe even full-text search?
|
||||
* rss
|
||||
|
@ -337,7 +337,7 @@ struct Event {
|
||||
}
|
||||
|
||||
void preprocessEventContent(lmdb::txn &txn, Decompressor &decomp, UserCache &userCache, std::string &content, bool withLinks = true) const {
|
||||
static RE2 matcher(R"((?is)(.*?)(https?://\S+|#\[\d+\]|nostr:(?:note|npub)1\w+))");
|
||||
static RE2 matcher(R"((?is)(.*?)(https?://\S+|#\[\d+\]|nostr:(?:note|npub|nevent|nprofile)1\w+))");
|
||||
|
||||
std::string output;
|
||||
|
||||
@ -367,6 +367,19 @@ struct Event {
|
||||
std::string path = "/e/";
|
||||
path += sv(match).substr(6);
|
||||
appendLink(path, sv(match));
|
||||
} else if (match.starts_with("nostr:nevent1")) {
|
||||
bool didTransform = false;
|
||||
|
||||
try {
|
||||
auto id = decodeBech32GetSpecial(sv(match).substr(6));
|
||||
std::string path = "/e/";
|
||||
path += encodeBech32Simple("note", id);
|
||||
|
||||
appendLink(path, sv(match));
|
||||
didTransform = true;
|
||||
} catch(...) {}
|
||||
|
||||
if (!didTransform) output += sv(match);
|
||||
} else if (match.starts_with("nostr:npub1")) {
|
||||
bool didTransform = false;
|
||||
|
||||
@ -374,9 +387,18 @@ struct Event {
|
||||
const auto *u = userCache.getUser(txn, decomp, decodeBech32Simple(sv(match).substr(6)));
|
||||
appendLink(std::string("/u/") + u->npubId, std::string("@") + u->username);
|
||||
didTransform = true;
|
||||
} catch(std::exception &e) {
|
||||
//LW << "tag parse error: " << e.what();
|
||||
}
|
||||
} catch(...) {}
|
||||
|
||||
if (!didTransform) output += sv(match);
|
||||
} else if (match.starts_with("nostr:nprofile")) {
|
||||
bool didTransform = false;
|
||||
|
||||
try {
|
||||
auto pubkey = decodeBech32GetSpecial(sv(match).substr(6));
|
||||
const auto *u = userCache.getUser(txn, decomp, pubkey);
|
||||
appendLink(std::string("/u/") + u->npubId, std::string("@") + u->username);
|
||||
didTransform = true;
|
||||
} catch(...) {}
|
||||
|
||||
if (!didTransform) output += sv(match);
|
||||
} else if (match.starts_with("#[")) {
|
||||
|
@ -37,6 +37,8 @@ namespace bech32
|
||||
namespace
|
||||
{
|
||||
|
||||
const size_t BECH32_MAX_SIZE = 5000;
|
||||
|
||||
typedef std::vector<uint8_t> data;
|
||||
|
||||
/** The Bech32 character set for encoding. */
|
||||
@ -204,7 +206,7 @@ DecodeResult decode(const std::string& str) {
|
||||
}
|
||||
if (lower && upper) return {};
|
||||
size_t pos = str.rfind('1');
|
||||
if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
|
||||
if (str.size() > BECH32_MAX_SIZE || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
|
||||
return {};
|
||||
}
|
||||
data values(str.size() - 1 - pos);
|
||||
|
Reference in New Issue
Block a user