diff --git a/pinnwand/gist.sh b/pinnwand/gist.sh index fd3c196..7c91556 100755 --- a/pinnwand/gist.sh +++ b/pinnwand/gist.sh @@ -1,15 +1,35 @@ #!/bin/bash -# SPDX-License-Identifier: GPL-3.0-or-later +### +# Paste to a Pinnwand pastebin service +# +# This script uploads text content from files or stdin to a Pinnwand +# pastebin instance. It supports specifying expiry times, lexers for +# syntax highlighting. +# +# Features: +# - Upload content from files or stdin +# - Specify expiry times and lexers for syntax highlighting +# - Supports autodetection (if enabled by the server) or explicit +# lexer selection +# +# Dependencies: +# - curl: For sending HTTP requests to the Pinnwand API +# - jq: For parsing JSON responses and encoding input +# - file: For binary file detection +# +# SPDX-License-Identifier: CC0-1.0 +### # Base URL of the Pinnwand instance -PINNWAND_BASE_URL="https://gist.tnonline.net/api/v1" +PINNWAND_BASE_URL="${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" +lexer="autodetect" # Function to show help information show_help() { @@ -19,10 +39,13 @@ show_help() { Usage: $s [options] [file1 file2 ...] Options: - -e, --expiry Set the expiry time for the paste (e.g., 1day, 1hour). - Default is '1day' if not specified. + -e, --expiry Set the expiry time for the paste (e.g., 1day, + 1hour). Default is '1day' if not specified. + --expiries List valid expiry periods. -l, --lexer Specify the lexer to use for syntax highlighting. - --lexers List all available lexers in 'name : description' format. + Default is 'autodetect' if not specified. + --lexers List all available lexers in 'name : description' + format. -h, --help Show this help message and exit. Examples: @@ -33,18 +56,13 @@ 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 + # Use the `file` command to check if the input is binary + [[ "$(file --mime-encoding -b -L "$input")" == "binary" ]] } # Function to post content to Pinnwand @@ -53,7 +71,14 @@ post_to_pinnwand() { local lexer="$2" shift 2 local files=("$@") - + + # Create temporary files for payload and response + tmp_payload=$(mktemp 2>/dev/null) || { echo "Error: Failed to create a temporary file for payload"; exit 1; } + tmp_response=$(mktemp 2>/dev/null) || { echo "Error: Failed to create a temporary file for response"; rm -f "$tmp_payload"; exit 1; } + tmp_status=$(mktemp 2>/dev/null) || { echo "Error: Failed to create a temporary file for status code"; rm -f "$tmp_payload" "$tmp_response"; exit 1; } + tmp_stdin=$(mktemp 2>/dev/null) || { echo "Error: Failed to create a temporary file for stdin"; rm -f "$tmp_payload" "$tmp_response" "$tmp_status"; exit 1; } + trap 'rm -f "$tmp_payload" "$tmp_response" "$tmp_status" "$tmp_stdin"' EXIT + # Prepare files array for JSON files_json="[" @@ -61,13 +86,12 @@ post_to_pinnwand() { # 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 @@ -76,31 +100,55 @@ post_to_pinnwand() { fi done else - # If no files were provided, read from stdin - stdin_content=$(cat | jq -Rs .) # Read and JSON-encode stdin content + # Write stdin to a temp file + cat > "$tmp_stdin" + # Check if stdin content is binary - if is_binary "$stdin_content"; then + if is_binary "$tmp_stdin"; then echo "Error: Input from stdin is binary. Only text content is allowed." exit 1 fi + + # Read and JSON-encode stdin content + stdin_content=$(<"$tmp_stdin" jq -Rs .) 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"'}' ) + echo '{"expiry":"'"$expiry"'","files":'"$files_json"'}' > "$tmp_payload" + # Send the payload using curl and save the response and HTTP status separately + curl -s -o "$tmp_response" -w "%{http_code}" -X POST "$PASTE_URL" \ + -H "Content-Type: application/json" --data @"$tmp_payload" > "$tmp_status" - # Extract link and removal URLs from the response - link=$(echo "$response" | jq -r '.link') - removal=$(echo "$response" | jq -r '.removal') + # Extract HTTP status code and response body + http_code=$(<"$tmp_status") + response_body=$(<"$tmp_response") - # Check if the response contains a URL - if [[ "$response" == null ]]; then - echo "Error: Could not create paste" + # Ensure http_code is a valid number + if ! [[ "$http_code" =~ ^[0-9]{3}$ ]]; then + echo "Error: Failed to parse HTTP status code. Raw response:" + cat "$tmp_response" + exit 1 + fi + + # Check if the HTTP status code indicates success + if [[ "$http_code" -ne 200 ]]; then + echo "Error: Failed to create paste (HTTP $http_code). Response body:" + echo "$response_body" + exit 1 + fi + + # Extract link and removal URLs from the response body + link=$(echo "$response_body" | jq -r '.link') + removal=$(echo "$response_body" | jq -r '.removal') + + # Check if the response contains valid URLs + if [[ -z "$link" || "$link" == "null" ]]; then + echo "Error: Could not create paste. API response:" + echo "$response_body" exit 1 else echo "Paste URL: $link" @@ -108,6 +156,22 @@ post_to_pinnwand() { fi } +# Function to fetch and list available expiry times +list_expiries() { + local expiries + + # Fetch expiry options from the API + expiries=$(curl -s "$PINNWAND_BASE_URL/expiry" | jq -r 'keys_unsorted | join(" ")' 2>/dev/null) + + if [[ -z "$expiries" ]]; then + echo "Error: Unable to fetch valid expiry options from the server." + exit 1 + fi + + echo "Valid expiry times: $expiries" + exit 0 +} + # Function to list available lexers list_lexers() { curl -s "$LEXER_URL" | jq -r '.' @@ -118,16 +182,27 @@ list_lexers() { while [ "$#" -gt 0 ]; do case $1 in -e|--expiry) + if [[ -z "$2" || "$2" == -* ]]; then + echo "Error: The --expiry option requires a value." + exit 1 + fi expiry="$2" shift 2 ;; -l|--lexer) + if [[ -z "$2" || "$2" == -* ]]; then + echo "Error: The --lexer option requires a value." + exit 1 + fi lexer="$2" shift 2 ;; --lexers) list_lexers ;; + --expiries) + list_expiries + ;; -h|--help) show_help ;; @@ -142,3 +217,4 @@ files=("$@") # Post content from provided files or stdin post_to_pinnwand "$expiry" "$lexer" "${files[@]}" +