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);
|
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));
|
auto res = bech32::decode(std::string(v));
|
||||||
|
|
||||||
if (res.encoding == bech32::Encoding::INVALID) throw herr("invalid bech32");
|
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;
|
std::vector<uint8_t> out;
|
||||||
if (!convertbits<5, 8, false>(out, res.data)) throw herr("convertbits failed");
|
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());
|
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
|
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
|
* 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?
|
* search field: enter anything, pubkey (hex or npub), eventId, etc. maybe even full-text search?
|
||||||
* rss
|
* rss
|
||||||
|
@ -337,7 +337,7 @@ struct Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void preprocessEventContent(lmdb::txn &txn, Decompressor &decomp, UserCache &userCache, std::string &content, bool withLinks = true) const {
|
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;
|
std::string output;
|
||||||
|
|
||||||
@ -367,6 +367,19 @@ struct Event {
|
|||||||
std::string path = "/e/";
|
std::string path = "/e/";
|
||||||
path += sv(match).substr(6);
|
path += sv(match).substr(6);
|
||||||
appendLink(path, sv(match));
|
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")) {
|
} else if (match.starts_with("nostr:npub1")) {
|
||||||
bool didTransform = false;
|
bool didTransform = false;
|
||||||
|
|
||||||
@ -374,9 +387,18 @@ struct Event {
|
|||||||
const auto *u = userCache.getUser(txn, decomp, decodeBech32Simple(sv(match).substr(6)));
|
const auto *u = userCache.getUser(txn, decomp, decodeBech32Simple(sv(match).substr(6)));
|
||||||
appendLink(std::string("/u/") + u->npubId, std::string("@") + u->username);
|
appendLink(std::string("/u/") + u->npubId, std::string("@") + u->username);
|
||||||
didTransform = true;
|
didTransform = true;
|
||||||
} catch(std::exception &e) {
|
} catch(...) {}
|
||||||
//LW << "tag parse error: " << e.what();
|
|
||||||
}
|
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);
|
if (!didTransform) output += sv(match);
|
||||||
} else if (match.starts_with("#[")) {
|
} else if (match.starts_with("#[")) {
|
||||||
|
@ -37,6 +37,8 @@ namespace bech32
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const size_t BECH32_MAX_SIZE = 5000;
|
||||||
|
|
||||||
typedef std::vector<uint8_t> data;
|
typedef std::vector<uint8_t> data;
|
||||||
|
|
||||||
/** The Bech32 character set for encoding. */
|
/** The Bech32 character set for encoding. */
|
||||||
@ -204,7 +206,7 @@ DecodeResult decode(const std::string& str) {
|
|||||||
}
|
}
|
||||||
if (lower && upper) return {};
|
if (lower && upper) return {};
|
||||||
size_t pos = str.rfind('1');
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
data values(str.size() - 1 - pos);
|
data values(str.size() - 1 - pos);
|
||||||
|
Reference in New Issue
Block a user