2024-05-03 16:15:40 +08:00
|
|
|
# include <filesystem>
|
|
|
|
# include <iostream>
|
|
|
|
# include <regex>
|
|
|
|
# include <hpcstat/ssh.hpp>
|
|
|
|
# include <hpcstat/keys.hpp>
|
|
|
|
# include <hpcstat/env.hpp>
|
|
|
|
# include <hpcstat/common.hpp>
|
|
|
|
# include <fmt/format.h>
|
|
|
|
# include <boost/filesystem.hpp>
|
|
|
|
# include <boost/process.hpp>
|
|
|
|
# include <boost/dll.hpp>
|
|
|
|
|
|
|
|
namespace hpcstat::ssh
|
|
|
|
{
|
|
|
|
std::optional<std::string> fingerprint()
|
|
|
|
{
|
|
|
|
if (auto datadir = env::env("HPCSTAT_DATADIR", true); !datadir)
|
|
|
|
return std::nullopt;
|
|
|
|
else if
|
|
|
|
(
|
|
|
|
auto output =
|
|
|
|
exec(std::filesystem::path(*datadir) / "ssh-add", { "-l" });
|
|
|
|
!output
|
|
|
|
)
|
|
|
|
{ std::cerr << "Failed to get ssh fingerprints\n"; return std::nullopt; }
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::regex pattern(R"r(\b(?:sha|SHA)256:([0-9A-Za-z+/=]{43})\b)r");
|
|
|
|
std::smatch match;
|
|
|
|
for
|
|
|
|
(
|
|
|
|
auto i = std::sregex_iterator(output->begin(), output->end(), pattern);
|
2024-05-04 11:57:13 +08:00
|
|
|
i != std::sregex_iterator(); ++i
|
2024-05-03 16:15:40 +08:00
|
|
|
)
|
|
|
|
if (Keys.contains(i->str(1))) return i->str(1);
|
|
|
|
std::cerr << fmt::format("No valid fingerprint found in:\n{}\n", *output);
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::optional<std::string> sign(std::string message, std::string fingerprint)
|
|
|
|
{
|
|
|
|
if (auto datadir = env::env("HPCSTAT_DATADIR", true); !datadir)
|
|
|
|
return std::nullopt;
|
|
|
|
else if
|
|
|
|
(
|
|
|
|
auto output = exec
|
|
|
|
(
|
|
|
|
std::filesystem::path(*datadir) / "ssh-keygen",
|
|
|
|
{
|
2024-05-03 18:47:37 +08:00
|
|
|
"-Y", "sign", "-q",
|
2024-05-03 16:15:40 +08:00
|
|
|
"-f", fmt::format("{}/keys/{}", *datadir, Keys[fingerprint].PubkeyFilename),
|
|
|
|
"-n", "hpcstat@chn.moe", "-"
|
|
|
|
},
|
|
|
|
message
|
|
|
|
);
|
|
|
|
!output
|
|
|
|
)
|
|
|
|
{ std::cerr << fmt::format("Failed to sign message: {}\n", message); return std::nullopt; }
|
|
|
|
else return *output;
|
|
|
|
}
|
|
|
|
bool verify(std::string message, std::string signature, std::string fingerprint)
|
|
|
|
{
|
|
|
|
if (auto datadir = env::env("HPCSTAT_DATADIR", true); !datadir)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
namespace bf = boost::filesystem;
|
|
|
|
auto tempdir = bf::temp_directory_path() / bf::unique_path();
|
|
|
|
bf::create_directories(tempdir);
|
|
|
|
auto signaturefile = tempdir / "signature";
|
|
|
|
std::ofstream(signaturefile) << signature;
|
|
|
|
return exec
|
|
|
|
(
|
|
|
|
std::filesystem::path(*datadir) / "ssh-keygen",
|
|
|
|
{
|
|
|
|
"-Y", "verify",
|
|
|
|
"-f", fmt::format("{}/keys/{}", *datadir, Keys[fingerprint].PubkeyFilename),
|
|
|
|
"-n", "hpcstat@chn.moe", "-s", signaturefile.string()
|
|
|
|
},
|
|
|
|
message
|
|
|
|
).has_value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|