133 lines
2.9 KiB
C++
133 lines
2.9 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));
|
|
proc->termKill(std::chrono::milliseconds(1));
|
|
|
|
reader.waitFor();
|
|
|
|
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;
|
|
}
|