bb64/bb64.cpp
2025-05-13 20:34:06 +12:00

147 lines
4.2 KiB
C++

#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <cstring>
#include <sstream>
#include <filesystem>
#include "version.h"
#include "b64ed.hpp"
// Recursively decode and print if nested bb64 command is found
void recursive_print(const std::string &decoded)
{
std::cout << std::string(80, '-') << std::endl;
std::cout << decoded << std::endl;
std::cout << std::string(80, '-') << std::endl;
size_t pos = decoded.find("bb64 ");
if (pos != std::string::npos)
{
std::istringstream iss(decoded.substr(pos));
std::string cmd, arg;
iss >> cmd >> arg;
if (cmd == "bb64" && !arg.empty())
{
std::string nested = base64_decode(arg);
std::cout << " ";
std::cout << "nested: " << nested << std::endl;
recursive_print(nested);
}
}
}
constexpr unsigned int hash(const char *s, int off = 0)
{
return !s[off] ? 5381 : (hash(s, off + 1) * 33) ^ s[off];
}
std::string get_arch()
{
// determine the architecture of the system
std::string arch;
#ifdef __aarch64__
arch = "arm64";
#elif __x86_64__
arch = "amd64";
#endif
return arch;
}
int update_bb64()
{
// determine path to this executable
std::filesystem::path bb64_path = std::filesystem::canonical("/proc/self/exe");
std::filesystem::path parent_path = bb64_path.parent_path();
// determine the architecture of the system
std::string arch = get_arch();
std::string url = "https://gitea.jde.nz/public/bb64/releases/download/latest/bb64." + arch;
// download new version, preserve permissions and ownership
std::string bash_script;
bash_script += "docker run --rm -v "+parent_path.string()+":/target";
bash_script += " gitea.jde.nz/public/debian-curl:latest";
bash_script += " sh -c \"";
bash_script += " curl -fsSL " + url + " -o /target/bb64_temp &&";
bash_script += " chmod --reference=/target/bb64 /target/bb64_temp &&";
bash_script += " chown --reference=/target/bb64 /target/bb64_temp &&";
bash_script += " mv /target/bb64_temp /target/bb64";
bash_script += "\"";
std::cout << "Updating " << bb64_path << " to the latest " << arch << " version." << std::endl;
// std::cout << "bash_script: " << std::endl
// << bash_script << std::endl;
// run the bash script
execlp("bash", "bash", "-c", bash_script.c_str(), (char *)nullptr);
std::cerr << "Failed to execute command." << std::endl;
return -1;
}
int decode_and_run(const std::string &encoded)
{
// Default: decode and run
std::string decoded = base64_decode(encoded);
if (decoded.empty())
{
std::cerr << "Failed to decode base64 command." << std::endl;
return -1;
}
// Replace current process with bash -c "decoded"
execlp("bash", "bash", "-c", decoded.c_str(), (char *)nullptr);
// If execlp returns, there was an error
std::cerr << "Failed to execute command." << std::endl;
return -1;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cerr << "bb64 version " << VERSION << ", by J842." << std::endl;
// heredoc for instructions
std::cerr << R"(
Usage:
bb64 BASE64COMMAND Decodes and runs the command
bb64 -[i|d] BASE64COMMAND Displays the decoded command
bb64 -e COMMAND Encodes the command and prints the result
bb64 -u Updates bb64 to the latest version (uses docker)
)" << std::endl;
return -1;
}
std::string mode = argv[1];
if (argc == 2)
{
if (mode == "-u")
return update_bb64();
else
return decode_and_run(mode);
}
std::ostringstream oss;
switch (hash(mode.c_str()))
{
case hash("-i"):
case hash("-d"):
std::cout << "Decoding command..." << std::endl
<< std::endl;
recursive_print(base64_decode(argv[2]));
break;
case hash("-e"):
for (int i = 2; i < argc; ++i)
oss << (i > 2 ? " " : "") << argv[i];
std::cout << base64_encode(oss.str()) << std::endl;
break;
default:
std::cerr << "Invalid mode: " << mode << std::endl;
return -1;
};
}