Compare commits

..

No commits in common. "main" and "v7" have entirely different histories.
main ... v7

10 changed files with 148 additions and 385 deletions

69
.vscode/settings.json vendored
View File

@ -1,69 +0,0 @@
{
"files.associations": {
"*.inja": "jinja-html",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp",
"format": "cpp",
"__nullptr": "cpp",
"codecvt": "cpp"
}
}

View File

@ -1,42 +1,27 @@
# bb64
# Installation
Automated system-wide installation:
```
curl -fsSL https://gitea.jde.nz/public/bb64/releases/download/latest/install.sh | bash
```
## To download just the bb64 executable:
```
curl -fsSL -o bb64 https://gitea.jde.nz/public/bb64/releases/download/latest/bb64.amd64 && chmod a+x bb64
```
# Use
Bash Base64, written in C++.
Uses a custom Base64 character set for bash compatibility, not compatible with other utilities.
Useage:
bb64 BASE64COMMAND Decodes the base64 encoded command, and runs it
bb64 -i BASE64COMMAND Decodes the base64 encoded command, and prints to the screen
If it contains a bb64 command within the decoded command, it
also decodes that and prints it to the screen.
bb64 -e COMMAND(S) encodes the commands in base64, equivalent to echo "COMMAND" | base64.
```
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)
```
# Implementation Notes
bb64 runs the command by replacing the current process, so it ensures that tty, environment
variables etc are all identical for the run command. It works with interactive commands, like
nano or ssh.
bb64 supports bash scripts, as the command is run as:
`bash -c 'COMMAND'`
The command is run as:
bash -c COMMAND
Where COMMAND is passed to bash as a single argument.
If the command is run, the return value is the return value of the command.
If it isn't run, bb64 returns -1.
./build.sh will build bb64 for x86_64 (amd64) and arm64 architectures.
Uses it's own implementation of base64 decoding.

View File

@ -1,42 +0,0 @@
#include "b64ed.hpp"
#include <vector>
// Custom base64 encoding/decoding tables
static const std::string custom_base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+_";
std::string base64_encode(const std::string &in) {
std::string out;
int val = 0, valb = -6;
for (unsigned char c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back(custom_base64_chars[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6) out.push_back(custom_base64_chars[((val << 8) >> (valb + 8)) & 0x3F]);
while (out.size() % 4) out.push_back('=');
return out;
}
std::string base64_decode(const std::string &in) {
std::vector<int> T(256, -1);
for (int i = 0; i < 64; i++) T[custom_base64_chars[i]] = i;
std::string out;
int val = 0, valb = -8;
for (unsigned char c : in) {
if (T[c] == -1) break;
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val >> valb) & 0xFF));
valb -= 8;
}
}
return out;
}

View File

@ -1,9 +0,0 @@
#ifndef B64ED_HPP
#define B64ED_HPP
#include <string>
std::string base64_decode(const std::string &in);
std::string base64_encode(const std::string &in);
#endif

252
bb64.cpp
View File

@ -4,124 +4,105 @@
#include <unistd.h>
#include <cstring>
#include <sstream>
#include <filesystem>
#include "version.h"
#include "b64ed.hpp"
// Custom base64 encoding/decoding tables
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::string base64_encode(const std::string &in) {
std::string out;
int val = 0, valb = -6;
for (unsigned char c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back(base64_chars[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6) out.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]);
while (out.size() % 4) out.push_back('=');
return out;
}
std::string base64_decode(const std::string &in) {
std::vector<int> T(256, -1);
for (int i = 0; i < 64; i++) T[base64_chars[i]] = i;
std::string out;
int val = 0, valb = -8;
for (unsigned char c : in) {
if (T[c] == -1) break;
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val >> valb) & 0xFF));
valb -= 8;
}
}
return out;
}
// Recursively decode and print if nested bb64 command is found
void recursive_print(const std::string &decoded)
{
std::cout << std::string(80, '-') << std::endl;
void recursive_print(const std::string &decoded) {
std::cout << decoded << std::endl;
std::cout << std::string(80, '-') << std::endl;
size_t pos = decoded.find("bb64 ");
if (pos != std::string::npos)
{
if (pos != std::string::npos) {
std::istringstream iss(decoded.substr(pos));
std::string cmd, arg;
iss >> cmd >> arg;
if (cmd == "bb64" && !arg.empty())
{
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];
}
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cerr << "bb64 version " << VERSION << ", by J842." << std::endl;
// heredoc for instructions
std::cerr << R"(
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<unsigned char>(c) < 32 && c != ' ' && c != '\t' && c != '\n' && c != '\r') || static_cast<unsigned char>(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);
}
Usage:
bb64 BASE64COMMAND Decodes and runs the command
bb64 -i BASE64COMMAND Displays the decoded command
bb64 -e COMMAND Encodes the command and prints the result
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;
)" << std::endl;
return -1;
}
int decode_and_run(const std::string &encoded)
{
std::string mode;
int argi = 1;
if (std::string(argv[1]) == "-i" || std::string(argv[1]) == "-e") {
mode = argv[1];
argi = 2;
}
if (mode == "-e") {
// Encode the rest of the arguments as a single command string
std::ostringstream oss;
for (int i = argi; i < argc; ++i) {
if (i > argi) oss << " ";
oss << argv[i];
}
std::string encoded = base64_encode(oss.str());
std::cout << encoded << std::endl;
return 0;
} else if (mode == "-i") {
if (argi >= argc) {
std::cerr << "No BASE64COMMAND provided for -i" << std::endl;
return -1;
}
std::string decoded = base64_decode(argv[argi]);
recursive_print(decoded);
return 0;
} else {
// Default: decode and run
std::string decoded = base64_decode(encoded);
if (decoded.empty())
{
std::string decoded = base64_decode(argv[argi]);
if (decoded.empty()) {
std::cerr << "Failed to decode base64 command." << std::endl;
return -1;
}
@ -131,77 +112,4 @@ int decode_and_run(const std::string &encoded)
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;
};
}

View File

@ -8,13 +8,18 @@ mkdir -p "$OUTPUT_DIR"
# Build for x86_64 with musl static linking
if [[ $(uname -m) == "x86_64" ]]; then
echo "Building for x86_64 (musl static)..."
x86_64-linux-musl-g++ -O2 -static -o "$OUTPUT_DIR/bb64.amd64" bb64.cpp b64ed.cpp
if command -v x86_64-linux-musl-g++ &>/dev/null; then
x86_64-linux-musl-g++ -O2 -static -o "$OUTPUT_DIR/bb64.amd64" bb64.cpp
else
g++ -O2 -static -o "$OUTPUT_DIR/bb64.amd64" bb64.cpp -static-libgcc -static-libstdc++
echo "Warning: musl-g++ not found, built with g++ static flags."
fi
echo "Built bb64.amd64 (x86_64, static)"
fi
# Build for arm64 (musl static) if cross-compiler available
if command -v aarch64-linux-musl-g++ &>/dev/null; then
echo "Building for arm64 (musl static)..."
aarch64-linux-musl-g++ -O2 -static -o "$OUTPUT_DIR/bb64.arm64" bb64.cpp b64ed.cpp
aarch64-linux-musl-g++ -O2 -static -o "$OUTPUT_DIR/bb64.arm64" bb64.cpp
echo "Built bb64.arm64 (arm64, static)"
fi

View File

@ -1,31 +1,19 @@
#!/bin/bash
set -e
# Require root
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root." >&2
exit 1
fi
# Installs bb64 on the local machine.
# 1. determines the architecture of the local machine
# 2. downloads the appropriate bb64 binary from the latest public release on Gitea (https://gitea.jde.nz/public/bb64/releases)
# 2. downloads the appropriate bb64 binary from the latest public release on Gitea (https://gitea.jde.nz/j/bb64/releases)
# 3. makes the bb64 binary executable
# 4. moves the bb64 binary to /usr/local/bin
# 5. prints a message to the user
# 0. see if we were passed a folder to install to
# -----------------------------------------------------------------------------
INSTALL_DIR="$1"
if [[ -z "$INSTALL_DIR" ]]; then
INSTALL_DIR="/usr/local/bin"
else
echo "Installing bb64 to $INSTALL_DIR"
if [[ ! -d "$INSTALL_DIR" ]]; then
mkdir -p "$INSTALL_DIR"
fi
fi
# 0. see if we were passed a user to chown to
# -----------------------------------------------------------------------------
CHOWN_USER="$2"
if [[ -z "$CHOWN_USER" ]]; then
CHOWN_USER=$(id -u)
fi
# 1. Determine architecture
# -----------------------------------------------------------------------------
@ -40,14 +28,29 @@ else
exit 1
fi
# 2. Get latest release tag from Gitea API
# -----------------------------------------------------------------------------
REPO_API="https://gitea.jde.nz/api/v1/repos/j/bb64/releases"
if command -v jq >/dev/null 2>&1; then
TAG=$(curl -s "$REPO_API" | jq -r '.[0].tag_name')
else
TAG=$(curl -s "$REPO_API" | grep -m1 '"tag_name"' | sed 's/.*"tag_name"[ ]*:[ ]*"\([^"]*\)".*/\1/')
fi
if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then
echo "Could not determine latest release tag from $REPO_API" >&2
exit 1
fi
echo "Latest version of bb64 is: $TAG"
# 3. Download the appropriate binary to a temp directory
# -----------------------------------------------------------------------------
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
URL="https://gitea.jde.nz/public/bb64/releases/download/latest/$BIN"
URL="https://gitea.jde.nz/j/bb64/releases/download/$TAG/$BIN"
echo "Downloading $BIN from $URL..."
curl -fsSL -o "$TMPDIR/bb64" "$URL"
curl -L -o "$TMPDIR/bb64" "$URL"
# 4. Make it executable
# -----------------------------------------------------------------------------
@ -55,15 +58,11 @@ chmod +x "$TMPDIR/bb64"
# 5. Move to /usr/local/bin
# -----------------------------------------------------------------------------
docker run --rm -v "$TMPDIR:/tmp" -v "$INSTALL_DIR:/target" alpine sh -c "cp /tmp/bb64 /target/bb64; chown $CHOWN_USER /target/bb64"
rm "$TMPDIR/bb64"
mv "$TMPDIR/bb64" /usr/local/bin/bb64
# 6. Print success message
# -----------------------------------------------------------------------------
echo "bb64 installed successfully to $INSTALL_DIR/bb64 (arch $ARCH)"
# echo " "
# echo "Update bb64 with:"
# echo " bb64 -u"
# echo " "
# echo "try it out with:"
# echo " bb64 ZWNobyAiSGVsbG8td29ybGQhIGJiNjQgaXMgd29ya2luZy4i"
echo "bb64 installed successfully to /usr/local/bin/bb64 (version $TAG, arch $ARCH)"
echo " "
echo "try it out with:"
echo " bb64 ZWNobyAiSGVsbG8td29ybGQhIGJiNjQgaXMgd29ya2luZy4i"

View File

@ -39,15 +39,15 @@ if [ ! -d "$INSTALL_DIR/aarch64-linux-musl-cross" ]; then
fi
# Print instructions for adding to PATH
# cat <<EOF
cat <<EOF
# To use the musl cross compilers, add the following to your shell:
# export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:$PATH"
To use the musl cross compilers, add the following to your shell:
export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:$PATH"
# Or run:
# export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:\$PATH"
Or run:
export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:\$PATH"
# EOF
EOF
# Clean up
rm -rf "$TMPDIR"

View File

@ -17,9 +17,8 @@ if [ ! -f version.h ]; then
exit 1
else
v=$(cat version.h | grep -o 'static const char \*VERSION = "[0-9.]*";' | cut -d'"' -f2)
oldv=$v
v=$((v+1))
echo "Incrementing version from $oldv to $v" >&2
echo "Incrementing version from $v to $v" >&2
echo "static const char *VERSION = \"$v\";" > version.h
fi
TAG="v$v"
@ -27,10 +26,6 @@ TAG="v$v"
# Build binaries
./build.sh
# make sure we've commited.
git add . && git commit -m "bb64 release $TAG" && git push
# Find repo info from .git/config
REPO_URL=$(git config --get remote.origin.url)
if [[ ! $REPO_URL =~ gitea ]]; then
@ -77,24 +72,15 @@ if [ -z "$RELEASE_ID" ]; then
exit 1
fi
# Upload binaries and install.sh
for FILE in bb64.amd64 bb64.arm64 install.sh; do
if [ -f "output/$FILE" ]; then
filetoupload="output/$FILE"
elif [ -f "$FILE" ]; then
filetoupload="$FILE"
else
continue
fi
# Auto-detect content type
ctype=$(file --mime-type -b "$filetoupload")
curl -s -X POST "$API_URL/releases/$RELEASE_ID/assets?name=$FILE" \
-H "Content-Type: $ctype" \
# Upload binaries
for BIN in bb64.amd64 bb64.arm64; do
if [ -f "output/$BIN" ]; then
curl -s -X POST "$API_URL/releases/$RELEASE_ID/assets?name=$BIN" \
-H "Content-Type: application/octet-stream" \
-H "Authorization: token $TOKEN" \
--data-binary @"$filetoupload"
echo "Uploaded $FILE to release $TAG as $ctype."
--data-binary @"output/$BIN"
echo "Uploaded $BIN to release $TAG."
fi
done
echo "Published bb64 version $v to $REPO_URL (tag $TAG) with binaries."

View File

@ -1 +1 @@
static const char *VERSION = "39";
static const char *VERSION = "5";