Created
September 23, 2025 15:20
-
-
Save BoxOfSnoo/adc6ebe9a329957ef60d1035f5187b58 to your computer and use it in GitHub Desktop.
Secure shellfish config file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # include this from .bashrc, .zshrc or | |
| # another shell startup file with: | |
| # source $HOME/.shellfishrc | |
| # | |
| # Running from Secure ShellFish | |
| # this gives access to: | |
| # openUrl to open pages or deeps links | |
| # pbcopy to copy text to iOS clipboard | |
| # pbpaste to paste from iOS clipboard | |
| # quicklook to preview files | |
| # runShortcut to run Shortcuts | |
| # setbarcolor to change toolbar color | |
| # sharesheet to invoke iOS share sheet | |
| # snip to add new snippets | |
| # textastic to edit files with Textastic | |
| # | |
| # In any terminal use: | |
| # thumbnail to write exif thumbnails | |
| # notify to post notifications | |
| # widget to change lock/home screen | |
| # widgets & apple watch complications | |
| # | |
| # | |
| # this part does nothing outside ShellFish | |
| if [[ "$LC_TERMINAL" = "ShellFish" ]]; then | |
| ios_printURIComponent() { | |
| awk 'BEGIN {while (y++ < 125) z[sprintf("%c", y)] = y | |
| while (y = substr(ARGV[1], ++j, 1)) | |
| q = y ~ /[a-zA-Z0-9]/ ? q y : q sprintf("%%%02X", z[y]) | |
| printf("%s", q)}' "$1" | |
| } | |
| ios_printBase64Component() { | |
| echo -n "$1" | base64 | |
| } | |
| which printf > /dev/null | |
| ios_hasPrintf=$? | |
| ios_printf() { | |
| if [ $ios_hasPrintf ]; then | |
| printf "$1" | |
| else | |
| awk "BEGIN {printf \"$1\"}" | |
| fi | |
| } | |
| ios_sequence() { | |
| if [[ -n "$TMUX" ]]; then | |
| OUTPUT=$( | |
| ios_printf '\033Ptmux;\033\033]' | |
| echo -n "$1" | tr -d '[:space:]' | |
| ios_printf '\a\033\\' ) | |
| else | |
| OUTPUT=$( | |
| ios_printf '\033]' | |
| echo -n "$1" | tr -d '[:space:]' | |
| ios_printf '\a' ) | |
| fi | |
| if [ -t 1 ] ; then | |
| echo -n $OUTPUT | |
| elif [[ -n "$SSH_TTY" ]]; then | |
| echo -n $OUTPUT > $SSH_TTY | |
| else | |
| echo >&2 'Standard output is not tty and there is no $SSH_TTY' | |
| fi | |
| } | |
| ios_sequence_spaced() { | |
| if [[ -n "$TMUX" ]]; then | |
| OUTPUT=$( | |
| ios_printf '\033Ptmux;\033\033]' | |
| echo -n "$1" | |
| ios_printf '\a\033\\' ) | |
| else | |
| OUTPUT=$( | |
| ios_printf '\033]' | |
| echo -n "$1" | |
| ios_printf '\a' ) | |
| fi | |
| if [ -t 1 ] ; then | |
| echo -n $OUTPUT | |
| elif [[ -n "$SSH_TTY" ]]; then | |
| echo -n $OUTPUT > $SSH_TTY | |
| else | |
| echo >&2 'Standard output is not tty and there is no $SSH_TTY' | |
| fi | |
| } | |
| # prepare fifo for communicating result back to shell | |
| ios_prepareResult() { | |
| FIFO=$(mktemp) | |
| rm -f $FIFO | |
| mkfifo $FIFO | |
| echo $FIFO | |
| } | |
| # wait for terminal to complete action | |
| ios_handleResult() { | |
| FIFO=$1 | |
| if [ -n "$FIFO" ]; then | |
| read <$FIFO -s | |
| rm -f $FIFO | |
| if [[ $REPLY = error* ]]; then | |
| echo "${REPLY#error=}" | base64 >&2 -d | |
| return 1 | |
| fi | |
| if [[ $REPLY = result* ]]; then | |
| echo "${REPLY#result=}" | base64 -d | |
| fi | |
| fi | |
| } | |
| sharesheet() { | |
| if [[ $# -eq 0 ]]; then | |
| if tty -s; then | |
| cat <<EOF | |
| Usage: sharesheet [FILE]... | |
| Present share sheet for files and directories. Alternatively you can pipe in text and call it without arguments. | |
| If arguments exist inside the Finder or Files app changes made are written back to the server. | |
| EOF | |
| return 0 | |
| fi | |
| fi | |
| FIFO=$(ios_prepareResult) | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;sharesheet://?ver=2&respond="}' | |
| ios_printBase64Component "$FIFO" | |
| awk 'BEGIN {printf "&pwd="}' | |
| ios_printBase64Component "$PWD" | |
| awk 'BEGIN {printf "&home="}' | |
| ios_printBase64Component "$HOME" | |
| for var in "$@" | |
| do | |
| awk 'BEGIN {printf "&path="}' | |
| ios_printBase64Component "$var" | |
| done | |
| if [[ $# -eq 0 ]]; then | |
| text=$(cat -) | |
| awk 'BEGIN {printf "&text="}' | |
| ios_printBase64Component "$text" | |
| fi | |
| ) | |
| ios_sequence "$OUTPUT" | |
| ios_handleResult "$FIFO" | |
| } | |
| quicklook() { | |
| if [[ $# -eq 0 ]]; then | |
| if tty -s; then | |
| cat <<EOF | |
| Usage: quicklook [FILE]... | |
| Show QuickLook preview for files and directories. Alternatively you can pipe in text and call it without arguments. | |
| EOF | |
| return 0 | |
| fi | |
| fi | |
| FIFO=$(ios_prepareResult) | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;quicklook://?ver=2&respond="}' | |
| ios_printBase64Component "$FIFO" | |
| awk 'BEGIN {printf "&pwd="}' | |
| ios_printBase64Component "$PWD" | |
| awk 'BEGIN {printf "&home="}' | |
| ios_printBase64Component "$HOME" | |
| for var in "$@" | |
| do | |
| awk 'BEGIN {printf "&path="}' | |
| ios_printBase64Component "$var" | |
| done | |
| if [[ $# -eq 0 ]]; then | |
| text=$(cat -) | |
| awk 'BEGIN {printf "&text="}' | |
| ios_printBase64Component "$text" | |
| fi | |
| ) | |
| ios_sequence "$OUTPUT" | |
| ios_handleResult "$FIFO" | |
| } | |
| textastic() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: textastic <text-file> | |
| Open in Textastic 9.5 or later. | |
| File must be in directory represented in the Files app to allow writing back edits. | |
| EOF | |
| else | |
| if [ ! -e "$1" ]; then | |
| touch "$1" | |
| fi | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;textastic://?ver=2&pwd="}' | |
| ios_printBase64Component "$PWD" | |
| awk 'BEGIN {printf "&home="}' | |
| ios_printBase64Component "$HOME" | |
| awk 'BEGIN {printf "&path="}' | |
| ios_printBase64Component "$1" | |
| ) | |
| ios_sequence "$OUTPUT" | |
| fi | |
| } | |
| setbarcolor() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: setbarcolor <css-style color> | |
| Set color of terminal toolbar color with values such as | |
| red, '#f00', '#ff0000', rgb(255,0,0), color(p3 1.0 0.0 0.0) | |
| EOF | |
| else | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;settoolbar://?ver=2&color="}' | |
| ios_printBase64Component "$1" | |
| ) | |
| ios_sequence "$OUTPUT" | |
| fi | |
| } | |
| openUrl() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: openUrl <url> | |
| Open URL on iOS. | |
| EOF | |
| else | |
| FIFO=$(ios_prepareResult) | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;open://?ver=2&respond="}' | |
| ios_printBase64Component "$FIFO" | |
| awk 'BEGIN {printf "&url="}' | |
| ios_printBase64Component "$1" | |
| ) | |
| ios_sequence "$OUTPUT" | |
| ios_handleResult "$FIFO" | |
| fi | |
| } | |
| runShortcut() { | |
| local baseUrl="shortcuts://run-shortcut" | |
| if [[ $1 == "--x-callback" ]]; then | |
| local baseUrl="shortcuts://x-callback-url/run-shortcut" | |
| shift | |
| fi | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: runShortcut [--x-callback] <shortcut-name> [input-for-shortcut] | |
| Run in Shortcuts app bringing back results if --x-callback is included. | |
| EOF | |
| else | |
| local name=$(ios_printURIComponent "$1") | |
| shift | |
| if [[ $* == "-" ]]; then | |
| local text=$(cat -) | |
| local input=$(ios_printURIComponent "$text") | |
| else | |
| local input=$(ios_printURIComponent "$*") | |
| fi | |
| openUrl "$baseUrl?name=$name&input=$input" | |
| fi | |
| } | |
| # copy standard input or arguments to iOS clipboard | |
| pbcopy() { | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "52;c;"} ' | |
| if [ $# -eq 0 ]; then | |
| base64 | tr -d '\n' | |
| else | |
| echo -n "$@" | base64 | tr -d '\n' | |
| fi | |
| ) | |
| ios_sequence "$OUTPUT" | |
| } | |
| # paste from iOS device clipboard to standard output | |
| pbpaste() { | |
| FIFO=$(ios_prepareResult) | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;pbpaste://?ver=2&respond="}' | |
| ios_printBase64Component "$FIFO" | |
| ) | |
| ios_sequence "$OUTPUT" | |
| ios_handleResult "$FIFO" | |
| } | |
| # create new snippets | |
| snip() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: snip <text for snippet> | |
| EOF | |
| else | |
| OUTPUT=$( | |
| awk 'BEGIN {printf "6;addsnippet://?ver=2&text="}' | |
| ios_printBase64Component "$*" | |
| ) | |
| ios_sequence "$OUTPUT" | |
| fi | |
| } | |
| # Secure ShellFish supports 24-bit colors | |
| export COLORTERM=truecolor | |
| # We need to pass through escape sequences through tmux | |
| if [[ -n "$TMUX" ]]; then | |
| # ignore error from old versions of tmux without this command | |
| tmux 2> /dev/null set -g allow-passthrough on || true | |
| fi | |
| if [[ -z "$INSIDE_EMACS" && $- = *i* ]]; then | |
| # tmux mouse mode enables scrolling with | |
| # swipe and mouse wheel | |
| if [[ -n "$TMUX" ]]; then | |
| tmux set -g mouse on | |
| fi | |
| # send the current directory using OSC 7 when showing prompt to | |
| # make filename detection work better for interactive shell | |
| update_terminal_cwd() { | |
| ios_sequence $( | |
| awk "BEGIN {printf \"7;%s\", \"file://$HOSTNAME\"}" | |
| ios_printURIComponent "$PWD" | |
| ) | |
| } | |
| if [ -n "$ZSH_VERSION" ]; then | |
| precmd() { update_terminal_cwd; } | |
| elif [[ $PROMPT_COMMAND != *"update_terminal_cwd"* ]]; then | |
| PROMPT_COMMAND="update_terminal_cwd${PROMPT_COMMAND:+; $PROMPT_COMMAND}" | |
| fi | |
| fi | |
| fi | |
| # this part works in any context | |
| thumbnail() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: thumbnail <image-file> [image-file-2] ... | |
| Add Exif thumnails to image files using ImageMagick convert and exiftool. | |
| EOF | |
| else | |
| # make sure ImageMagick and exiftool are available | |
| convert -version 1>/dev/null 2>/dev/null || { echo "ImageMagick convert needs to be installed"; return 1; } | |
| exiftool -v 1>/dev/null 2>/dev/null || { echo "exiftool needs to be installed"; return 1; } | |
| THUMBNAIL=/tmp/thumbnail.jpg | |
| for arg in "$@" | |
| do | |
| echo "$arg" | |
| convert "$arg" -thumbnail 160x120^ "$THUMBNAIL" | |
| exiftool -q -overwrite_original "-thumbnailimage<=$THUMBNAIL" "$arg" | |
| rm -f "$THUMBNAIL" | |
| done | |
| fi | |
| } | |
| # Updates Terminal Data widget in Secure ShellFish | |
| # | |
| # This command sends encrypted data through push notifications such | |
| # that it doesn't need to run from a Secure ShellFish terminal. | |
| widget() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: widget [target] <data> ... | |
| Update widget on device from which this function was installed with a number of content parameters that can be string, progress, icon, target, color, url or shortcut. | |
| Each argument type is derived from input, where the first argument is assumed to be a target if it matches a target configured on the widget. | |
| Progress has the form: 50% or 110/220 | |
| Icon must match valid SF Symbol name such as globe or terminal.fill | |
| Colors must be hex colours such as #000 #ff00ff where the color is used for later content and 'foreground' switches back to default colour | |
| Target is used to send different content to different widgets after configuring the widgets with different target identifiers which requires the pro unlock. The target parameter is never assumed unless --target is used and is effective until next --target parameter allowing updates of several widgets with a single command | |
| URL is used when tapping the widget and is assumed for arguments starting with https:// and other schemes are supported by using --url | |
| Shortcut works like URL running the Shortcut with the given name and is never assumed without --shortcut | |
| String is the fallback type if nothing else matches, but content type can be forced for next parameter with --progress, --icon, --color, --text or --target with something like: | |
| widget --text "50/100" | |
| You can update several widgets at once by using --target to send all parameters until the next --target to a particular widget. Updating several widgets at once allows more total updates per day. | |
| EOF | |
| return 0 | |
| fi | |
| local key=5fa86232ae8170c1ec16f085461c3b1967605c8dac3451c7e1031e9e956fbae4 | |
| local user=EHfDyr8cMWZcb4sKisCzw6jejfBe9g57iH9wC7dT | |
| local iv=ab5bbeb426015da7eedcee8bee3dffb7 | |
| local plain=$( | |
| echo Secure ShellFish Widget 2.0 | |
| for var in "$@" | |
| do | |
| echo -ne "$var" | base64 | |
| done) | |
| local base64=$(echo "$plain" | openssl enc -aes-256-cbc -base64 -K $key -iv $iv) | |
| curl -sS -X POST -H "Content-Type: text/plain" --data "$base64" "https://secureshellfish.app/push/?user=$user" | |
| } | |
| # Shows notification on your device with Secure ShellFish installed | |
| # optionally opening URL or running Shortcut when notification is | |
| # opened. | |
| # | |
| # This command sends encrypted data through push notifications such | |
| # that it doesn't need to run from a Secure ShellFish terminal. | |
| notify() { | |
| if [[ $# -eq 0 ]]; then | |
| cat <<EOF | |
| Usage: notify [--shortcut NameOfShortcut] [--url https://url.to.open/] [title] <body> ... | |
| EOF | |
| return 0 | |
| fi | |
| local key=5fa86232ae8170c1ec16f085461c3b1967605c8dac3451c7e1031e9e956fbae4 | |
| local user=EHfDyr8cMWZcb4sKisCzw6jejfBe9g57iH9wC7dT | |
| local iv=ab5bbeb426015da7eedcee8bee3dffb7 | |
| local plain=$( | |
| echo Secure ShellFish Notify 2.0 | |
| for var in "$@" | |
| do | |
| echo -ne "$var" | base64 | |
| done) | |
| local base64=$(echo "$plain" | openssl enc -aes-256-cbc -base64 -K $key -iv $iv) | |
| curl -sS -X POST -H "Content-Type: text/plain" --data "$base64" "https://secureshellfish.app/push/?user=$user&mutable" | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment