#include #include #include #include #include #include #include #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 tidy(const std::string &str) { std::string result; bool in_whitespace = false; for (char c : str) { // Remove non-printable characters except for whitespace (space, tab, newline, carriage return) if ((static_cast(c) < 32 && c != ' ' && c != '\t' && c != '\n' && c != '\r') || static_cast(c) == 127) { continue; } if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { if (!in_whitespace) { result += ' '; in_whitespace = true; } } else { result += c; in_whitespace = false; } } // Remove leading whitespace size_t start = result.find_first_not_of(' '); if (start == std::string::npos) return ""; // Remove trailing whitespace size_t end = result.find_last_not_of(' '); return result.substr(start, end - start + 1); } 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 base64 encoded result bb64 -e Encodes the command provided on stdin and prints the result bb64 -u Updates bb64 to the latest version (uses docker) bb64 -v Prints the version number )" << std::endl; return -1; } std::string mode = argv[1]; if (argc == 2) { if (mode == "-u") return update_bb64(); else if (mode == "-v") { std::cout << VERSION << std::endl; return 0; } else if (mode == "-e") { std::ostringstream oss; while (std::cin) { std::string line; std::getline(std::cin, line); oss << line << std::endl; } std::string tidier = tidy(oss.str()); std::cout << base64_encode(tidier) << std::endl; return 0; } else return decode_and_run(mode); } std::ostringstream oss; std::string tidier; 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]; tidier = tidy(oss.str()); std::cout << base64_encode(tidier) << std::endl; break; default: std::cerr << "Invalid mode: " << mode << std::endl; return -1; }; }