TelegramTUI/src/crypt.cpp

130 lines
2.8 KiB
C++

#include "crypt.h"
#include <chrono>
#include <fstream>
#define Y_FEATURES (Y_FEATURE_SUBPROCES | Y_FEATURE_STRING)
#include <y/str.h>
#include <y/subprocess.h>
#include <y/pipe/pipefeeder.h>
#include <y/pipe/pipereader.h>
static const std::string ConfigFile("./assignment.conf");
static const std::string Header("-----BEGIN PGP MESSAGE-----\n\n");
static const std::string Footer("\n-----END PGP MESSAGE-----");
static const std::string MyHeader("gpg: ");
Crypt::Crypt() {}
void Crypt::setKey(int64_t chatid, const std::string& keyfingerprint) {
chatKeyMap[chatid] = keyfingerprint;
dirty = true;
}
std::string Crypt::encryptForChat(int64_t chat, const std::string& message) {
std::map<int64_t, std::string>::iterator it = chatKeyMap.find(chat);
if(it == chatKeyMap.end()) {
// no key found
return "<key not found>";
}
Y::SubProcess::Builder builder("gpg");
builder
.setArgs({"-e", "--armor", "-r", it->second})
.setFDMode(Y::SubProcess::FD::ALL, Y::SubProcess::FDMode::Pipe)
;
if(!self.empty()) {
builder.addArgs({"--encrypt-to", self});
}
std::unique_ptr<Y::SubProcess> proc = builder.start();
std::string out;
Y::PipeFeeder feeder(&message, proc->getInFD());
Y::PipeReader reader(&out, proc->getOutFD());
feeder.start();
reader.start();
proc->waitFor(std::chrono::seconds(4));
if(out.size() > Footer.size() + Header.size() ) {
out.resize(out.size() - Footer.size());
return MyHeader + out.substr(Header.size());
}
return "<encryption failed>";
}
std::string Crypt::decryptFromChat(int64_t chat, const std::string& message) {
if(!Y::Str::startsWith(message, MyHeader)) {
// not a gpg message
return message;
}
/*
// needed for verification
std::map<int64_t, std::string>::iterator it = chatKeyMap.find(chat);
if(it == chatKeyMap.end()) {
// no key found
return "<key not found>";
}
*/
std::string prefixed = Header + message.substr(MyHeader.size()) + Footer;
Y::SubProcess::Builder builder("gpg");
builder
.setArgs({"-d"})
.setFDMode(Y::SubProcess::FD::ALL, Y::SubProcess::FDMode::Pipe)
;
std::unique_ptr<Y::SubProcess> proc = builder.start();
std::string out;
Y::PipeFeeder feeder(&prefixed, proc->getInFD());
Y::PipeReader reader(&out, proc->getOutFD());
feeder.start();
reader.start();
proc->waitFor(std::chrono::seconds(4));
return out;
}
void Crypt::save() {
if(!dirty) {
return;
}
std::ofstream out(ConfigFile);
for(std::map<int64_t, std::string>::const_iterator it = chatKeyMap.begin(); it != chatKeyMap.end(); ++it) {
out << it->first << ' ' << it->second << '\n';
}
out.flush();
out.close();
dirty = false;
}
void Crypt::load() {
chatKeyMap.clear();
std::ifstream in(ConfigFile);
while(in) {
std::string key;
int64_t chat = 0;
in >> chat >> key;
if(!key.empty()) {
if(chat == 0) {
self = key;
} else {
chatKeyMap[chat] = key;
}
}
}
dirty = false;
}