diff --git a/pinnwand/README.md b/pinnwand/README.md new file mode 100644 index 0000000..ce517cc --- /dev/null +++ b/pinnwand/README.md @@ -0,0 +1,48 @@ +# Pinnwand + +Pinnwand is a straightforward pastebin service designed for simplicity and ease of use. It provides a clean web interface to share and manage text snippets, code, or notes. It supports features like syntax highlighting, expiration times, and revocation. + +## Pinnwand Installer Script + +The Pinnwand installer script is a Bash script designed to automate the installation, upgrade, and setup of Pinnwand on a Linux system. It sets up and installs Pinnwand into a Python virtual environment, keeping it separate from the base system. + +### Prerequisites + +- Python 3.8 or higher with `pip` +- Git installed on the system. + +### Features + +1. **Automated Installation**: The script can install Pinnwand by cloning its repository and setting up a virtual environment. +2. **Upgrade Support**: It can update Pinnwand to the latest version, a specified Git reference or main development branch. +3. **Custom Source Testing**: A `USE_LOCAL_SRC` option allows using manually downloaded sources and avoids the `git` dependency. + +### Usage + +1. Clone or download the script. +2. Set the username, install path and source path in the script. +3. Run the script as the `pinnwand` user: + ```bash + sudo -u pinnwand-user ./pinnwand-installer.sh + ``` + +## Running pinnwand + +Create a `config.toml` with desired configuration options. + +An example config file is available in the source tree under `etc/pinnwand-toml-example`. + +### Manually +Specify the configuring file and the TCP/IP listening port on the command line. +```bash +sudo -u pinnwand-user path/to/pinnwand/venv/bin/pinnwand --configuration-path config.toml http --port 1234 +``` + +### OpenRC init.d script +The provided init scripts help you run pinnwand as a service on a OpenRC system such as Gentoo and Alpine Linux. + +1. Cooy `pinnwand.initd` to `/etc/init.d/pinnwand` +2. Cooy `pinnwand.confd` to `/etc/conf.d/pinnwand` +3. Set the correct user and path in `/etc/conf.d/pinnwand` +4. Run `rc-update add pinnwand` to enable autostart on boot. +5. Run `rc-service pinnwand start` to start pinnwand now. \ No newline at end of file diff --git a/pinnwand/gist.sh b/pinnwand/gist.sh new file mode 100755 index 0000000..51bc9eb --- /dev/null +++ b/pinnwand/gist.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +# Base URL of the Pinnwand instance +PINNWAND_BASE_URL="https://gist.tnonline.net/api/v1" +PASTE_URL="${PINNWAND_BASE_URL}/paste" +LEXER_URL="${PINNWAND_BASE_URL}/lexer" + +# Default options +expiry="1day" +lexer="text" + +# Function to show help information +show_help() { + local s + s=$(basename "$0") + cat < Set the expiry time for the paste (e.g., 1day, 1hour). + Default is '1day' if not specified. + -l, --lexer Specify the lexer to use for syntax highlighting. + Default is 'text' if not specified. + --lexers List all available lexers in 'name : description' format. + -h, --help Show this help message and exit. + +Examples: + $s -e 1hour -l python file1 file2 + $s --lexers + dmesg | $s -l kmsg +END + exit 0 +} + +# Function to check if a file or input is binary +is_binary() { + local input="$1" + + if [[ -f "$input" ]]; then + # If input is a file, check directly with file command + [[ "$(file --mime-encoding -b -L "$input")" == "binary" ]] + else + # If input is from stdin, use grep to check for binary content + grep -qI . <<< "$input" + return $? # Return 0 for text, non-zero for binary + fi +} + +# Function to post content to Pinnwand +post_to_pinnwand() { + local expiry="$1" + local lexer="$2" + shift 2 + local files=("$@") + + # Prepare files array for JSON + files_json="[" + + if [[ "${#files[@]}" -gt 0 ]]; then + # Add each file to the JSON array + for file in "${files[@]}"; do + if [[ -f "$file" ]]; then + + # Check if the file is binary + if is_binary "$file"; then + echo "Error: $file is a binary file. Only text files are allowed." + exit 1 + fi + + content=$(<"$file" jq -Rs .) # Read and JSON-encode file content + files_json+="{\"name\":\"$(basename "$file")\",\"lexer\":\"$lexer\",\"content\":$content}," + else + echo "File not found: $file" + exit 1 + fi + done + else + # If no files were provided, read from stdin + stdin_content=$(cat | jq -Rs .) # Read and JSON-encode stdin content + # Check if stdin content is binary + if is_binary "$stdin_content"; then + echo "Error: Input from stdin is binary. Only text content is allowed." + exit 1 + fi + files_json+="{\"name\":\"stdin\",\"lexer\":\"$lexer\",\"content\":$stdin_content}," + fi + + # Remove trailing comma and close array + files_json="${files_json%,}]" + + response=$(curl -s -X POST "$PASTE_URL" \ + -H "Content-Type: application/json" \ + -d '{"expiry":"'"$expiry"'","files":'"$files_json"'}' ) + + + # Extract link and removal URLs from the response + link=$(echo "$response" | jq -r '.link') + removal=$(echo "$response" | jq -r '.removal') + + # Check if the response contains a URL + if [[ "$response" == null ]]; then + echo "Error: Could not create paste" + exit 1 + else + echo "Paste URL: $link" + echo "Removal URL: $removal" + fi +} + +# Function to list available lexers +list_lexers() { + curl -s "$LEXER_URL" | jq -r '.' + exit 0 +} + +# Parse command line options +while [ "$#" -gt 0 ]; do + case $1 in + -e|--expiry) + expiry="$2" + shift 2 + ;; + -l|--lexer) + lexer="$2" + shift 2 + ;; + --lexers) + list_lexers + ;; + -h|--help) + show_help + ;; + *) + break + ;; + esac +done + +# Remaining arguments are assumed to be files +files=("$@") + +# Post content from provided files or stdin +post_to_pinnwand "$expiry" "$lexer" "${files[@]}" diff --git a/pinnwand/openrc/pinnwand.confd b/pinnwand/openrc/pinnwand.confd new file mode 100644 index 0000000..26d3c3e --- /dev/null +++ b/pinnwand/openrc/pinnwand.confd @@ -0,0 +1,32 @@ +### +# pinnwand init.d configuration +### + +# Path to the Pinnwand configuration file. +config_file="/home/pinnwand/pinnwand_config.toml" + +# User and group under which the Pinnwand service will run. +pinnwand_user="pinnwand:pinnwand" + +# Port on which the Pinnwand service will listen for HTTP requests.. +port=9000 + +# Path to the Pinnwand executable. +command="/home/pinnwand/venv/bin/pinnwand" + +# Directory where logs will be stored. +#log_dir="/var/log" + +# Path to the standard output log file for the Pinnwand service.. +#output_log="${log_dir}/pinnwand.log" + +# Path to the error log file for the Pinnwand service. +#error_log="${log_dir}/pinnwand.err" + +# Override arguments passed to the Pinnwand command at startup. +# -v: Enable verbose logging. +# --configuration-path: Specify the path to the configuration file. +# http: Start the HTTP server. +# --port: Specify the port on which the service will listen. + +#command_args="-v --configuration-path \"${config_file}\" http --port ${port}" diff --git a/pinnwand/openrc/pinnwand.initd b/pinnwand/openrc/pinnwand.initd new file mode 100755 index 0000000..e7dfc5b --- /dev/null +++ b/pinnwand/openrc/pinnwand.initd @@ -0,0 +1,24 @@ +#!/sbin/openrc-run + +description="Pinnwand pastebin service" + +config_file="${config_file:-/home/pinnwand/pinnwand_config.toml}" +port="${port:-9000}" +log_dir="${log_dir:-/var/log}" +output_log="${output_log:-$log_dir/$RC_SVCNAME.log}" +error_log="${error_log:-$log_dir/$RC_SVCNAME.err}" +pidfile="${pidfile:-/run/$RC_SVCNAME.pid}" +command="${command:-/home/pinnwand/venv/bin/pinnwand}" +command_user="${pinnwand_user:-pinnwand:pinnwand}" +command_args="${command_args:- --configuration-path \"$config_file\" http --port $port}" +command_background=true + +start_pre() { + if [ ! -f "$config_file" ]; then + eerror "Configuration file not found: $config_file" + return 1 + fi + + checkpath --file --owner "$command_user" --mode 0664 "$output_log" + checkpath --file --owner "$command_user" --mode 0664 "$error_log" +} diff --git a/pinnwand/pinnwand-installer.sh b/pinnwand/pinnwand-installer.sh new file mode 100755 index 0000000..8800438 --- /dev/null +++ b/pinnwand/pinnwand-installer.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Variables +USER="pinnwand" +HOME_DIR="/home/${USER}" +VENV_DIR="${HOME_DIR}/venv" +SRC_DIR="${HOME_DIR}/src" +PINNWAND_SRC="${SRC_DIR}/pinnwand" +USE_LOCAL_SRC="false" # Set to "true" to skip Git updates +REPO_URL="https://github.com/supakeen/pinnwand.git" +# Set to a specific tag (e.g., v1.6.0) or use "master" for the latest branch. Leave empty for automatic selection of latest release. +# GIT_REF="v1.6.0" + +get_latest_tag_remote() { + latest_tag=$(git ls-remote --tags "$REPO_URL" v\* | awk -F'/' '{print $3}' | sort -V | tail -n 1) + echo "$latest_tag" +} + +# Ensure the script is run as the specified user +if [ "$(whoami)" != "$USER" ]; then + echo "This script must be run as the '$USER' user." + echo "Try 'sudo -u $USER $0'" + exit 1 +fi + +# Check if the source directory exists +if [ ! -d "$SRC_DIR" ]; then + echo "Source directory '$SRC_DIR' does not exist. Please create it and try again." + exit 1 +fi + +# Update or use the existing repository +if [ "$USE_LOCAL_SRC" = "true" ]; then + echo "USE_LOCAL_SRC is set. Skipping Git updates and using the local source as is." + if [ ! -d "$PINNWAND_SRC" ]; then + echo "Pinnwand source directory not found." + fi +else + # Detect the latest tag if GIT_REF is not set + GIT_REF="${GIT_REF:-}" + + if [ -z "$GIT_REF" ]; then + echo "GIT_REF is not set. Detecting the latest tag from remote..." + GIT_REF=$(get_latest_tag_remote) + [ -z "$GIT_REF" ] && { echo "Failed to determine the latest tag."; exit 1; } + echo "Using the latest tag: $GIT_REF" + fi + + if [ ! -d "$PINNWAND_SRC" ]; then + echo "Pinnwand source directory not found. Cloning the repository..." + git clone "$REPO_URL" "$PINNWAND_SRC" || { echo "Failed to clone repository."; exit 1; } + else + echo "Pinnwand source directory found. Cleaning and updating from Git..." + pushd "$PINNWAND_SRC" > /dev/null || { echo "Failed to navigate to $PINNWAND_SRC."; exit 1; } + + # Clean untracked files and directories first + git clean -q -fd || { echo "Failed to clean untracked files."; exit 1; } + + # Reset the repository to ensure a clean state + git fetch -q --all || { echo "Failed to fetch updates from repository."; exit 1; } + git reset -q --hard "$GIT_REF" || { echo "Failed to reset to $GIT_REF."; exit 1; } + + popd > /dev/null + fi +fi + +echo "Source preparation complete." + +exit +# Check if the virtual environment exists and is valid; create it if necessary +if [ ! -d "$VENV_DIR" ]; then + echo "Virtual environment not found. Creating it now..." + python3 -m venv "$VENV_DIR" || { echo "Failed to create virtual environment."; exit 1; } +elif [ ! -f "${VENV_DIR}/bin/activate" ]; then + echo "Virtual environment directory exists but is invalid. Recreating it..." + python3 -m venv "$VENV_DIR" || { echo "Failed to recreate virtual environment."; exit 1; } +fi + +# Ensure pip is upgraded +echo "Upgrading pip..." +"${VENV_DIR}/bin/pip" install --upgrade pip || { echo "Failed to upgrade pip."; exit 1; } + +# Install or upgrade Pinnwand from the source +echo "Installing/Upgrading Pinnwand from source..." +"${VENV_DIR}/bin/pip" install -v "$PINNWAND_SRC" || { echo "Failed to install Pinnwand."; exit 1; } + +# Return to the original directory +popd || { echo "Failed to return to original directory."; exit 1; } + +echo "Pinnwand installation/upgrade process completed successfully." \ No newline at end of file