Compare commits

...

34 Commits
v10 ... main

Author SHA1 Message Date
Your Name
a01e9f9856 bb64 release v39 2025-05-19 00:22:38 +12:00
Your Name
745c7a8c9c bb64 release v38 2025-05-18 23:42:35 +12:00
Your Name
78e3a9af97 bb64 release v37 2025-05-17 17:09:43 +12:00
Your Name
97582f0381 . 2025-05-17 12:41:54 +12:00
Your Name
374df9f580 bb64 release v36 2025-05-17 09:56:57 +12:00
Your Name
dd7bfe3f30 tiny fixes 2025-05-17 09:56:15 +12:00
Your Name
3356da8cf7 bb64 release v35 2025-05-17 08:04:18 +12:00
Your Name
8f17ecdbdc bb64 release v34 2025-05-17 08:03:25 +12:00
Your Name
868c1c9c57 bb64 release v33 2025-05-14 22:55:33 +12:00
Your Name
f6d4ecce59 bb64 release v32 2025-05-14 22:30:21 +12:00
Your Name
f83f0cb874 bb64 release v31 2025-05-14 22:10:02 +12:00
Your Name
bc607d239d bb64 release v30 2025-05-14 22:02:14 +12:00
Your Name
e6b84a8d8c bb64 release v29 2025-05-13 20:34:06 +12:00
Your Name
eb89974d78 bb64 release v28 2025-05-12 22:10:33 +12:00
Your Name
5e7203b3b9 bb64 release v27 2025-05-12 22:05:33 +12:00
Your Name
7081615a98 bb64 release v26 2025-05-12 22:02:56 +12:00
Your Name
8b184a524f bb64 release v25 2025-05-12 21:56:52 +12:00
Your Name
61718ecacd bb64 release v24 2025-05-12 21:55:03 +12:00
Your Name
928bf05196 public 2025-05-12 21:54:16 +12:00
Your Name
5af5399508 bb64 release v23 2025-05-12 21:21:55 +12:00
Your Name
1339150167 bb64 release v22 2025-05-12 21:11:33 +12:00
Your Name
c67fb1447b bb64 release v21 2025-05-12 21:09:26 +12:00
Your Name
207b27a07e bb64 release v20 2025-05-12 21:09:00 +12:00
Your Name
02559d1519 bb64 release v19 2025-05-12 21:06:51 +12:00
Your Name
cd58e1cf81 bb64 release v18 2025-05-12 21:06:32 +12:00
Your Name
78abea2761 bb64 release v17 2025-05-12 21:06:09 +12:00
Your Name
56429455b4 bb64 release v16 2025-05-12 21:02:48 +12:00
Your Name
ae67bccf47 bb64 release v15 2025-05-12 21:02:02 +12:00
Your Name
61b61ca93d bb64 release v14 2025-05-12 21:00:26 +12:00
Your Name
798e95dca4 bb64 release v13 2025-05-12 20:59:44 +12:00
Your Name
90c22fea00 bb64 release v12 2025-05-12 20:43:11 +12:00
Your Name
6b11a45e0f Use latest release API method 2025-05-12 20:39:00 +12:00
Your Name
ee702d92ca bb64 release v11 2025-05-12 20:32:18 +12:00
Your Name
d544b8953d . 2025-05-12 20:31:38 +12:00
8 changed files with 212 additions and 77 deletions

View File

@ -63,6 +63,7 @@
"typeinfo": "cpp", "typeinfo": "cpp",
"variant": "cpp", "variant": "cpp",
"format": "cpp", "format": "cpp",
"__nullptr": "cpp" "__nullptr": "cpp",
"codecvt": "cpp"
} }
} }

View File

@ -2,10 +2,18 @@
# Installation # Installation
Automated system-wide installation:
``` ```
curl -fsSL -o bb64_install.sh https://gitea.jde.nz/j/bb64/raw/branch/main/install.sh && sudo bash ./bb64_install.sh && rm bb64_install.sh 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 # Use
Bash Base64, written in C++. Bash Base64, written in C++.
@ -13,12 +21,11 @@ Bash Base64, written in C++.
Uses a custom Base64 character set for bash compatibility, not compatible with other utilities. Uses a custom Base64 character set for bash compatibility, not compatible with other utilities.
``` ```
Useage: Usage:
bb64 BASE64COMMAND Decodes the base64 encoded command, and runs it bb64 BASE64COMMAND Decodes and runs the command
bb64 -i BASE64COMMAND Decodes the base64 encoded command, and prints to the screen bb64 -[i|d] BASE64COMMAND Displays the decoded command
If it contains a bb64 command within the decoded command, it bb64 -e COMMAND Encodes the command and prints the result
also decodes that and prints it to the screen. bb64 -u Updates bb64 to the latest version (uses docker)
bb64 -e COMMAND(S) encodes the commands in base64.
``` ```
# Implementation Notes # Implementation Notes
@ -27,11 +34,9 @@ bb64 runs the command by replacing the current process, so it ensures that tty,
variables etc are all identical for the run command. It works with interactive commands, like variables etc are all identical for the run command. It works with interactive commands, like
nano or ssh. nano or ssh.
The command is run as: bb64 supports bash scripts, as the command is run as:
`bash -c COMMAND` `bash -c 'COMMAND'`
Where COMMAND is passed to bash as a single argument. 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 the command is run, the return value is the return value of the command.
If it isn't run, bb64 returns -1. If it isn't run, bb64 returns -1.
`./build.sh` will build bb64 for x86_64 (amd64) and arm64 architectures.

147
bb64.cpp
View File

@ -4,14 +4,16 @@
#include <unistd.h> #include <unistd.h>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <filesystem>
#include "version.h" #include "version.h"
#include "b64ed.hpp" #include "b64ed.hpp"
// Recursively decode and print if nested bb64 command is found // Recursively decode and print if nested bb64 command is found
void recursive_print(const std::string &decoded) void recursive_print(const std::string &decoded)
{ {
std::cout << std::string(80, '-') << std::endl;
std::cout << decoded << std::endl; std::cout << decoded << std::endl;
std::cout << std::string(80, '-') << std::endl;
size_t pos = decoded.find("bb64 "); size_t pos = decoded.find("bb64 ");
if (pos != std::string::npos) if (pos != std::string::npos)
@ -34,6 +36,102 @@ constexpr unsigned int hash(const char *s, int off = 0)
return !s[off] ? 5381 : (hash(s, off + 1) * 33) ^ s[off]; 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<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);
}
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[]) int main(int argc, char *argv[])
{ {
if (argc < 2) if (argc < 2)
@ -45,41 +143,62 @@ int main(int argc, char *argv[])
Usage: Usage:
bb64 BASE64COMMAND Decodes and runs the command bb64 BASE64COMMAND Decodes and runs the command
bb64 -[i|d] BASE64COMMAND Displays the decoded command bb64 -[i|d] BASE64COMMAND Displays the decoded command
bb64 -e COMMAND Encodes the command and prints the result
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; )" << std::endl;
return -1; return -1;
} }
std::string mode = argv[1];
if (argc == 2) if (argc == 2)
{ {
// Default: decode and run if (mode == "-u")
std::string decoded = base64_decode(argv[1]); return update_bb64();
if (decoded.empty()) else if (mode == "-v")
{ {
std::cerr << "Failed to decode base64 command." << std::endl; std::cout << VERSION << std::endl;
return -1; return 0;
} }
// Replace current process with bash -c "decoded" else if (mode == "-e")
execlp("bash", "bash", "-c", decoded.c_str(), (char *)nullptr); {
// If execlp returns, there was an error std::ostringstream oss;
std::cerr << "Failed to execute command." << std::endl; while (std::cin)
return -1; {
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::string mode = argv[1];
std::ostringstream oss; std::ostringstream oss;
std::string tidier;
switch (hash(mode.c_str())) switch (hash(mode.c_str()))
{ {
case hash("-i"): case hash("-i"):
case hash("-d"): case hash("-d"):
std::cout << "Decoding command..." << std::endl
<< std::endl;
recursive_print(base64_decode(argv[2])); recursive_print(base64_decode(argv[2]));
break; break;
case hash("-e"): case hash("-e"):
for (int i = 2; i < argc; ++i) for (int i = 2; i < argc; ++i)
oss << (i > 2 ? " " : "") << argv[i]; oss << (i > 2 ? " " : "") << argv[i];
std::cout << base64_encode(oss.str()) << std::endl; tidier = tidy(oss.str());
std::cout << base64_encode(tidier) << std::endl;
break; break;
default: default:
std::cerr << "Invalid mode: " << mode << std::endl; std::cerr << "Invalid mode: " << mode << std::endl;

View File

@ -8,12 +8,7 @@ mkdir -p "$OUTPUT_DIR"
# Build for x86_64 with musl static linking # Build for x86_64 with musl static linking
if [[ $(uname -m) == "x86_64" ]]; then if [[ $(uname -m) == "x86_64" ]]; then
echo "Building for x86_64 (musl static)..." echo "Building for x86_64 (musl static)..."
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 b64ed.cpp
x86_64-linux-musl-g++ -O2 -static -o "$OUTPUT_DIR/bb64.amd64" bb64.cpp b64ed.cpp
else
g++ -O2 -static -o "$OUTPUT_DIR/bb64.amd64" bb64.cpp b64ed.cpp -static-libgcc -static-libstdc++
echo "Warning: musl-g++ not found, built with g++ static flags."
fi
echo "Built bb64.amd64 (x86_64, static)" echo "Built bb64.amd64 (x86_64, static)"
fi fi

View File

@ -1,19 +1,31 @@
#!/bin/bash #!/bin/bash
set -e 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. # Installs bb64 on the local machine.
# 1. determines the architecture of 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/j/bb64/releases) # 2. downloads the appropriate bb64 binary from the latest public release on Gitea (https://gitea.jde.nz/public/bb64/releases)
# 3. makes the bb64 binary executable # 3. makes the bb64 binary executable
# 4. moves the bb64 binary to /usr/local/bin # 4. moves the bb64 binary to /usr/local/bin
# 5. prints a message to the user # 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 # 1. Determine architecture
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -28,26 +40,11 @@ else
exit 1 exit 1
fi 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 # 3. Download the appropriate binary to a temp directory
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
TMPDIR=$(mktemp -d) TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT trap 'rm -rf "$TMPDIR"' EXIT
URL="https://gitea.jde.nz/j/bb64/releases/download/$TAG/$BIN" URL="https://gitea.jde.nz/public/bb64/releases/download/latest/$BIN"
echo "Downloading $BIN from $URL..." echo "Downloading $BIN from $URL..."
curl -fsSL -o "$TMPDIR/bb64" "$URL" curl -fsSL -o "$TMPDIR/bb64" "$URL"
@ -58,11 +55,15 @@ chmod +x "$TMPDIR/bb64"
# 5. Move to /usr/local/bin # 5. Move to /usr/local/bin
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
mv "$TMPDIR/bb64" /usr/local/bin/bb64 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"
# 6. Print success message # 6. Print success message
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
echo "bb64 installed successfully to /usr/local/bin/bb64 (version $TAG, arch $ARCH)" echo "bb64 installed successfully to $INSTALL_DIR/bb64 (arch $ARCH)"
echo " " # echo " "
echo "try it out with:" # echo "Update bb64 with:"
echo " bb64 ZWNobyAiSGVsbG8td29ybGQhIGJiNjQgaXMgd29ya2luZy4i" # echo " bb64 -u"
# 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 fi
# Print instructions for adding to PATH # Print instructions for adding to PATH
cat <<EOF # cat <<EOF
To use the musl cross compilers, add the following to your shell: # 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" # export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:$PATH"
Or run: # Or run:
export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:\$PATH" # export PATH="$INSTALL_DIR/x86_64-linux-musl-cross/bin:$INSTALL_DIR/aarch64-linux-musl-cross/bin:\$PATH"
EOF # EOF
# Clean up # Clean up
rm -rf "$TMPDIR" rm -rf "$TMPDIR"

View File

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

View File

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