note.cpp
updates:
- removed markdown
```cpp
#ifndef QNOSTRRELAY_H
#define QNOSTRRELAY_H
#include
#include
#include
#include
#include
#include
#include
#include "qtnostr_global.h"
QT_BEGIN_NAMESPACE
class LIBQTNOSTR_CORE_EXPORT QNostrRelay : public QObject
{
Q_OBJECT
class Private;
friend class QNostr;
public:
struct LIBQTNOSTR_CORE_EXPORT Event {
std::optional
std::optional
std::optional
int kind;
QList
QString content;
std::optional
QJsonArray tagsArray() const;
QString serialize() const;
static Event deserialize(const QJsonObject &obj);
};
struct LIBQTNOSTR_CORE_EXPORT Request {
std::optional
QStringList ids;
QStringList authors;
QList
QStringList e;
QStringList p;
std::optional
std::optional
int limit = 1;
QString serialize() const;
};
struct LIBQTNOSTR_CORE_EXPORT Close {
QString subscriptionId;
QString serialize() const;
};
QNostrRelay(const QUrl &relay, const QString &secretKey, QObject *parent = nullptr);
QNostrRelay(const QUrl &relay, const QString &publicKey, const QString &privateKey, QObject *parent = nullptr);
virtual ~QNostrRelay();
public Q_SLOTS:
void start();
void stop();
QString sendEvent(const QString &content);
QString sendEvent(Event event, bool prepared = false);
QString sendRequest(Request request);
void sendClose(const Close &request);
void sendClose(const QString &subscriptionId);
static void prepareEvent(Event &event, const QByteArray &publicKey, const QByteArray &privateKey);
static QByteArray compressedPublicKey(const QString &secretKey);
static QByteArray extractPrivateKey(const QByteArray& base64SecretKey);
Q_SIGNALS:
void failed(const QString &id, const QString &reason);
void successfully(const QString &id);
void error(QAbstractSocket::SocketError error);
void sslErrors(const QList
void newEvent(const QString &subscribeId, const Event &event, bool storedEvent);
void notice(const QString &msg);
void syncEventsFinished(const QString &subscribeId);
void disconnected();
void connected();
protected:
static QString calculateId(const Event &event);
static QByteArray sign(const QByteArray &data, const QByteArray &privateKey);
private:
void serverConnected();
void serverDisonnected();
void analizeData(const QString &data);
void init();
private:
Private *p;
};
QT_END_NAMESPACE
#endif // QNOSTRRELAY_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int CHECKSUM_LENGTH = 6;
const std::string CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
QWidget* window;
QBoxLayout* events_container;
QLabel* pk_label;
QLineEdit * filename_input;
QTextEdit* textEdit;
QString secret;
QString pk;
QString pk_hex;
QNostr* nostr;
QWebSocket* socket;
std::unordered_map
std::vector
std::vector
for (size_t i = 0; i < prefix.length(); i++) {
char code = prefix[i];
outBuffer[i] = code >> 5;
outBuffer[i + prefix.length() + 1] = code & 31;
}
outBuffer[prefix.length()] = 0;
return outBuffer;
}
std::vector
std::vector
std::vector
for (size_t i = 0; i < prefixBuffer.size(); i++) {
dst[i] = prefixBuffer[i];
}
for (size_t i = 0; i < message.length(); i++) {
dst[2 * prefix.length() + 1 + i] = CHAR_LOOKUP[message[i]];
}
return dst;
}
std::vector
std::string lowerCaseMsg = message;
std::transform(lowerCaseMsg.begin(), lowerCaseMsg.end(), lowerCaseMsg.begin(), ::tolower);
size_t sepIdx = lowerCaseMsg.find_last_of('1');
std::string prefix = lowerCaseMsg.substr(0, sepIdx);
std::string suffix = lowerCaseMsg.substr(sepIdx + 1);
std::vector
return std::vector
}
std::vector
size_t len = (src.size() * 5) / 8;
std::vector
int acc = 0;
int bits = 0;
int dstIndex = 0;
for (size_t i = 0; i < src.size(); i++) {
acc = (acc << 5) | src[i];
bits += 5;
while (bits >= 8) {
bits -= 8;
dst[dstIndex++] = (acc >> bits) & 0xFF;
}
}
return dst;
}
std::string toHex(const std::vector
std::string hex;
for (uint8_t b : data) {
std::bitset<8> bits(b);
std::stringstream ss;
ss << std::hex << bits.to_ulong();
std::string temp = ss.str();
if (temp.length() == 1) {
temp = "0" + temp;
}
hex += temp;
}
return hex;
}
QString bech32tohex(QString id){
if(id.length() != 63){
return id;
}
std::vector
std::vector
return QString::fromStdString(toHex(result));
}
void add_note_button(QString eid){
QPushButton* event_button = new QPushButton(eid.left(15), window);
events_container->addWidget(event_button);
QObject::connect(event_button, &QPushButton::clicked, [eid](){
textEdit->setText(eid);
});
}
void save_privkey(QString key){
QFile file("note_privkey.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << key;
}
QString load_privkey(){
QFile file("note_privkey.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){
QString sk = QNostr::generateNewSecret();
save_privkey(sk);
return sk;
}
return QString(file.readLine());
}
void load_notes(){
QFile file("mynotes.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
while (!file.atEnd()) {
QString eid = QString(file.readLine()).trimmed();
add_note_button(eid);
}
}
void append_note(QString eid){
QFile file("mynotes.txt");
if (!file.open(QIODevice::Append | QIODevice::Text))
return;
QTextStream out(&file);
out << eid << "\n";
}
/*QString request_named_note(QString name){
const QString eid = bech32tohex(textEdit->toPlainText());
QNostrRelay::Request req;
req.authors << pk;
req["#d"] = name;
relay.sendRequest(req);
}*/
int main(int argc, char **argv) {
QApplication app(argc, argv);
window = new QWidget;
events_container = new QBoxLayout(QBoxLayout::TopToBottom);
for (size_t i = 0; i < CHARSET.length(); i++) {
CHAR_LOOKUP[CHARSET[i]] = i;
}
secret = load_privkey();
nostr = new QNostr(secret);
pk_hex = QByteArray::fromBase64(nostr->publicKey().toLocal8Bit(), QByteArray::Base64Encoding)
.mid(1).toHex().toLower();
pk = QNostrRelay::compressedPublicKey(secret);
QFont font;
font.setPointSize(18);
window->setWindowTitle("note.cpp | nostr notepad");
window->setFont(font);
window->resize(1280, 800);
textEdit = new QTextEdit(window);
textEdit->setAcceptRichText(false);
textEdit->setPlaceholderText("write a message or paste eventid");
filename_input = new QLineEdit(window);
filename_input->setPlaceholderText("filename");
QPushButton* eid_button = new QPushButton("", window);
eid_button->setFlat(true);
eid_button->setEnabled(false);
QPushButton* send_button = new QPushButton("Send", window);
QPushButton* query_button = new QPushButton("Query", window);
QGridLayout layout = QGridLayout(window);
window->setLayout(&layout);
layout.addWidget(filename_input, 0, 0, 1, 2);
layout.addWidget(textEdit, 1, 0, 1, 2);
layout.addWidget(send_button, 2, 0);
layout.addWidget(query_button, 2, 1);
layout.addLayout(events_container, 0, 2, 3, 1, Qt::AlignTop);
pk_label = new QLabel(pk_hex.left(25), window);
events_container->addWidget(pk_label);
load_notes();
window->show();
socket = new QWebSocket();
socket->open(QUrl("wss://nos.lol"));
QObject::connect(send_button, &QPushButton::clicked, [](){
QString content = textEdit->toPlainText();
QNostrRelay::Event event;
event.kind = 1;
QStringList dtag;
dtag << "d" << filename_input->text();
event.tags << dtag;
event.content = content;
QNostrRelay::prepareEvent(event, pk.toLocal8Bit(), QNostrRelay::extractPrivateKey(secret.toLatin1()));
QString event_str = event.serialize();
socket->sendTextMessage(event.serialize());
add_note_button(event.id.value());
append_note(event.id.value());
textEdit->setText("");
filename_input->setText("");
});
QObject::connect(query_button, &QPushButton::clicked, [](){
const QString eid = bech32tohex(textEdit->toPlainText());
QNostrRelay::Request req;
req.subscriptionId = "q";
req.ids << eid;
socket->sendTextMessage(req.serialize());
});
QNostr::connect(socket, &QWebSocket::textMessageReceived, [](const QString &message) {
QJsonDocument jsonDoc = QJsonDocument::fromJson(message.toUtf8());
QJsonArray jsonArray = jsonDoc.array();
QString dvalue = QString("");
if(jsonArray.at(0).toString() == "EVENT"){
QString content = jsonArray.at(2).toObject().value("content").toString();
QJsonArray tags = jsonArray.at(2).toObject().value("tags").toArray();
for (int i = 0; i < tags.size(); i++) {
QJsonArray tag = tags.at(i).toArray();
if(tag.at(0).toString() == "d"){
dvalue = tag.at(1).toString();
break;
}
}
filename_input->setText(dvalue);
textEdit->setText(content);
}
});
app.exec();
}
```