From 6cce4bd5e7e89406c0ca5942076c95c458bba2dc Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Fri, 22 May 2020 08:38:40 -0500 Subject: Ready to upload --- bollux.sh | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100755 bollux.sh (limited to 'bollux.sh') diff --git a/bollux.sh b/bollux.sh new file mode 100755 index 0000000..84786b6 --- /dev/null +++ b/bollux.sh @@ -0,0 +1,264 @@ +#!/usr/bin/env bash +# bollux: bash gemini client +# Author: Case Duckworth +# License: MIT +# Version: -0.9 + +PRGN="${0##*/}" +PORT=1965 +LOG_LEVEL=3 # higher=more important. + +clean() { + # '\e[?7h': re-enable line wrapping + # '\e[2J': clear the screen + # '\e[;r': reset the scroll area + # '\e[?1049l': swap back to primary screen + printf '\e[?7h\e[2J\e[;r\e[?1049l' + exit +} + +refresh() { + # grab the terminal size + shopt -s checkwinsize + ( + : + : + ) + # '\e[?1049h': Swap to the alternate buffer. + # '\e[?7l': Disable line wrapping. + # '\e[2J': Clear the screen. + # '\e[3;%sr': Set the scroll area. + # '\e[999H': Move the cursor to the bottom. + printf '\e[?1049h\e[?7l\e[2J\e[3;%sr\e[999H' "$((LINES - 1))" +} + +resize() { + refresh + # '\e7': Save the cursor position. + # '\e[?25l': Hide the cursor. + # '\r': Move the cursor to column 0. + # '\e[999B': Move the cursor to the bottom. + # '\e[A': Move the cursor up a line. + printf '\e7\e[?25l\r\e[999B\e[A' +} + +bollux() { + if [[ -n "$1" ]]; then + loc="$1" + else + read -rp "GO> " loc + fi + + log 2 "location: $loc" + log 2 "address: $(address "$loc")" + log 2 "server: $(server "$loc")" + + address "$loc" | + download "$(server "$loc")" | + handle +} + +log() { + case "$1" in + [0-9]*) + lvl="$1" + shift + ;; + *) lvl=5 ;; + esac + if ((lvl >= LOG_LEVEL)); then + if [[ "$2" == - ]]; then + while IFS= read -r line; do + printf '\e[33m%s\e[0m:\t%s\n' "$PRGN" "$line" >&2 + done + else + printf '\e[34m%s\e[0m:\t%s\n' "bollux" "$*" >&2 + fi + fi +} + +download() { + # usage: + # echo REQUEST | download SERVER + # download SERVER REQUEST + serv="$1" + req= + if (($# == 2)); then + req="$2" + else + req="$(cat)" + fi + t="$(mktemp)" + openssl s_client -crlf -ign_eof -quiet -connect "$serv" <<<"$req" 2>"$t" + log 1 <"$t" + rm "$t" +} + +address() { + addr="$1" + if [[ "$addr" != gemini://* ]]; then + addr="gemini://$addr" + fi + echo "$addr" | trim +} + +server() { + serv="${1#*://}" + serv="${serv%%/*}" + if [[ "$serv" != *:* ]]; then + serv="$serv:$PORT" + fi + echo "$serv" | trim +} + +trim() { + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' +} + +display() { + echo + cat + echo +} + +handle() { + # cf. gemini://gemini.circumlunar.space/docs/spec-spec.txt + resp="$(cat)" + head="$(head -n1 <<<"$resp")" + body="$(tail -n+2 <<<"$resp")" + stat="$(awk '{print $1}' <<<"$head")" + smsg="$( + awk '{for(i=2;i<=NF;i++)printf "%s ",$i;printf "\n";}' <<<"$head" + )" + + log "[$stat] $smsg" + + case "$stat" in + 10) # INPUT + # As per definition of single-digit code 1 in 1.3.2. + NOT_IMPLEMENTED + ;; + 20) # SUCCESS + # As per definition of single-digit code 2 in 1.3.2. + display <<<"$body" + ;; + 21) # SUCCESS - END OF CLIENT CERTIFICATE SESSION + # The request was handled successfully and a response body will + # follow the response header. The line is a MIME media + # type which applies to the response body. In addition, the + # server is signalling the end of a transient client certificate + # session which was previously initiated with a status 61 + # response. The client should immediately and permanently + # delete the certificate and accompanying private key which was + # used in this request. + display <<<"$body" + NOT_FULLY_IMPLEMENTED + ;; + 30) # REDIRECT - TEMPORARY + # As per definition of single-digit code 3 in 1.3.2. + exec "$0" "$smsg" + ;; + 31) # REDIRECT - PERMANENT + # The requested resource should be consistently requested from + # the new URL provided in future. Tools like search engine + # indexers or content aggregators should update their + # configurations to avoid requesting the old URL, and end-user + # clients may automatically update bookmarks, etc. Note that + # clients which only pay attention to the initial digit of + # status codes will treat this as a temporary redirect. They + # will still end up at the right place, they just won't be able + # to make use of the knowledge that this redirect is permanent, + # so they'll pay a small performance penalty by having to follow + # the redirect each time. + exec "$0" "$smsg" + NOT_FULLY_IMPLEMENTED + ;; + 4*) # 40 - TEMPORARY FAILURE + # As per definition of single-digit code 4 in 1.3.2. + # 41 - SERVER UNAVAILABLE + # The server is unavailable due to overload or maintenance. + # (cf HTTP 503) + # 42 - CGI ERROR + # A CGI process, or similar system for generating dynamic + # content, died unexpectedly or timed out. + # 43 - PROXY ERROR + # A proxy request failed because the server was unable to + # successfully complete a transaction with the remote host. + # (cf HTTP 502, 504) + # 44 - SLOW DOWN + # Rate limiting is in effect. is an integer number of + # seconds which the client must wait before another request is + # made to this server. + # (cf HTTP 429) + printf 'OH SHIT!\n%s\t%s\n' "$stat" "$smsg" >&2 + NOT_IMPLEMENTED + ;; + 5*) # 50 - PERMANENT FAILURE + # As per definition of single-digit code 5 in 1.3.2. + # 51 - NOT FOUND + # The requested resource could not be found but may be available + # in the future. + # (cf HTTP 404) + # (struggling to remember this important status code? Easy: + # you can't find things hidden at Area 51!) + # 52 - GONE + # The resource requested is no longer available and will not be + # available again. Search engines and similar tools should + # remove this resource from their indices. Content aggregators + # should stop requesting the resource and convey to their human + # users that the subscribed resource is gone. + # (cf HTTP 410) + # 53 - PROXY REQUEST REFUSED + # The request was for a resource at a domain not served by the + # server and the server does not accept proxy requests. + # 59 - BAD REQUEST + # The server was unable to parse the client's request, + # presumably due to a malformed request. + # (cf HTTP 400) + printf 'OH SHIT!\n%s\t%s\n' "$stat" "$smsg" >&2 + NOT_IMPLEMENTED + ;; + 6*) # 60 - CLIENT CERTIFICATE REQUIRED + # As per definition of single-digit code 6 in 1.3.2. + # 61 - TRANSIENT CERTIFICATE REQUESTED + # The server is requesting the initiation of a transient client + # certificate session, as described in 1.4.3. The client should + # ask the user if they want to accept this and, if so, generate + # a disposable key/cert pair and re-request the resource using it. + # The key/cert pair should be destroyed when the client quits, + # or some reasonable time after it was last used (24 hours? + # Less?) + # 62 - AUTHORISED CERTIFICATE REQUIRED + # This resource is protected and a client certificate which the + # server accepts as valid must be used - a disposable key/cert + # generated on the fly in response to this status is not + # appropriate as the server will do something like compare the + # certificate fingerprint against a white-list of allowed + # certificates. The client should ask the user if they want to + # use a pre-existing certificate from a stored "key chain". + # 63 - CERTIFICATE NOT ACCEPTED + # The supplied client certificate is not valid for accessing the + # requested resource. + # 64 - FUTURE CERTIFICATE REJECTED + # The supplied client certificate was not accepted because its + # validity start date is in the future. + # 65 - EXPIRED CERTIFICTE REJECTED + # The supplied client certificate was not accepted because its + # expiry date has passed. + printf 'OH SHIT!\n%s\t%s\n' "$stat" "$smsg" >&2 + NOT_IMPLEMENTED + ;; + esac +} + +NOT_IMPLEMENTED() { + log "NOT IMPLEMENTED!!!" >&2 + exit 127 +} +NOT_FULLY_IMPLEMENTED() { + log "NOT FULLY IMPLEMENTED!!!" >&2 +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + bollux "$@" +fi -- cgit 1.4.1-21-gabe81