repo: shell-daemons
action: blob
revision: 
path_from: geminid
revision_from: refs/heads/master:
path_to: 
revision_to: 
git.thebackupbox.net
shell-daemons
git clone git://git.thebackupbox.net/shell-daemons

blob of:

shell-daemons

/ geminid

blob_plain of this file

refs/heads/master:/geminid

 #!/bin/bash
 # This work is marked with CC0 1.0. To view a copy of this license, visit http://creativecommons.org/publicdomain/zero/1.0

 if [ "$1" = "" ];then
 export SCHEME="gemini"
 export SERVER_SOFTWARE="epoch-geminid/0.1"
 export SERVER_PROTOCOL="gemini/0.1"
 export LANG=C.UTF-8

 if ! read -rt 10 REQUEST_URI;then
   logger -t geminid -p crit "request from ${REMOTE_ADDR} timed out after 10 seconds. bailing."
   exit 0
 fi

 REQUEST_METHOD="$(cut '-d ' -f1 <<< "$REQUEST_URI")"
 if [ "${REQUEST_METHOD}" = "GET" ];then
   printf 'HTTP/1.1 418 I am a teapot\r\n'
   printf 'Content-Type: text/plain\r\n\r\n'
   printf 'did you even look at the port? 1965. this is a gemini server. not an HTTP server.\n'
   printf 'I suggest you fuck off.'
   exit 0
 fi

 export REQUEST_URI=$(printf "%s\n" "${REQUEST_URI}" | tr -d '\r\n')
 export REQUEST_DOMAIN="$(printf "%s\n" "${REQUEST_URI}" | uricut -d | tr 'A-Z' 'a-z')"
 if [ ! "$REQUEST_DOMAIN" ];then
   REQUEST_DOMAIN=gemini.thebackupbox.net
 fi
 export REQUEST_PORT="$(printf "%s\n" "${REQUEST_URI}" | uricut -P)"
 if [ ! "$REQUEST_PORT" ];then
   REQUEST_PORT="${SERVER_PORT}"
 fi
 export REQUEST_SCHEME="$(printf "%s\n" "${REQUEST_URI}" | uricut -s)"

 if [ "$REQUEST_URI" = "" ];then
   logger -t geminid -p crit "$REMOTE_ADDR is sending an empty request. gonna just bail on this."
   exit 0
 fi

 logger -t geminid -p warn "request: $REQUEST_URI from: $REMOTE_ADDR"

 if ! printf "%s\n" "$REQUEST_URI" | urimatch nf 2>&1 >/dev/null;then
   logger -t geminid "someone requested with fragment!"
   export REQUEST_URI_ORIGINAL="$REQUEST_URI"
   export REQUEST_URI="$(printf "%s\n" "$REQUEST_URI" | cut '-d#' -f1)"
 fi


 # if we have SNI, we use that for SERVER_NAME,
 # otherwise we use what was in the gemini request.
 export SSL_TLS_SNI="$(printf "%s\n" "${SSL_TLS_SNI}" | tr 'A-Z' 'a-z')"
 if [ ! "${SSL_TLS_SNI}" ];then
   export SERVER_NAME="${SSL_TLS_SNI}"
 else
   export SERVER_NAME="${REQUEST_DOMAIN}"
 fi

 if [ "$SERVER_NAME" = "" ];then
   export SERVER_NAME=gemini.thebackupbox.net
 fi

 #export IDENT="$(printf "$REMOTE_PORT, $SERVER_PORT\r\n" | nc $REMOTE_ADDR 113)"

 #export IDENT="$(ident $SERVER_ADDR $REMOTE_ADDR 113 $REMOTE_PORT $SERVER_PORT)"
 # usage: ident.sh our-host their-host 113 their-port our-port
 ## not sure exactly what this should contain.

 if [ ! "${REQUEST_PORT}" ];then
   if [ "${REQUEST_SCHEME}" = "gemini" ];then
     export REQUEST_PORT=1965
   fi
 fi

 if [ ! "${SERVER_PORT}" ];then ### this should get overridden by whatever runs this script.
   export SERVER_PORT=1965
 fi

 REQUEST_DP="${REQUEST_DOMAIN}:${REQUEST_PORT}"
 SERVER_DP="${SSL_TLS_SNI}:${SERVER_PORT}"

 if [ "$SSL_TLS_SNI" = "" ];then
   SERVER_DP="gemini.thebackupbox.net:1965"
 fi

 if [ "${REQUEST_DP}" != "${SERVER_DP}" ];then
   if [ "${SSL_TLS_SNI}" = "epo.k.vu" ];then
     uristart "${REQUEST_URI}" 2>/dev/null
     exit 1
   fi
   printf "53 PROXY REQUEST REFUSED. requested (%s) != sni (%s)\r\n" "${REQUEST_DP}" "${SERVER_DP}"
   exit 1
 fi

 export REQUEST_PATH="/$(printf "%s\n" "${REQUEST_URI}" | uricut -p)"


 ### need to preserve trailing / through normalpath
 trailing_slash="$(printf "%s\n" "$REQUEST_PATH" | rev | cut -b1 | tr -cd '/')"
 export SCRIPT_NAME="$(normalpath "/$(uriunescape "$REQUEST_PATH")")${trailing_slash}"

 if [ "$SCRIPT_NAME" = "/~/" ];then
   printf "20 text/gemini\r\n"
   printf "# users with gemini sites here:\n"
   ls -d /home/*/public_gemini | cut -d/ -f3 | sed 's|^\(.*\)$|=> /~\1/ \1|g'
   exit 0
 fi

 ### 
 if grep '^/~' <<< "$SCRIPT_NAME" 2>&1 >/dev/null ;then
   export user="$(printf "%s\n" "$SCRIPT_NAME" | cut -d/ -f2 | tr -cd 'a-zA-Z0-9')"
   if ! cd "/$(getent passwd "$user" | cut -d: -f6)/public_gemini";then
     printf '59 BAD REQUEST (guru meditation: 1) "%s"\r\n' "$(getent passwd "$user" | cut -d: -f6)"
     exit 1
   fi
   export DROP_TO="$user"
   ### export SCRIPT_NAME="$(printf "%s\n" "$SCRIPT_NAME" | cut -d/ -f3-)"
   export SCRIPT_RELATIVE_FILENAME="$(printf "%s\n" "$SCRIPT_NAME" | cut -d/ -f3-)"
 else
   unset user
   export DROP_TO="gemini"
   cd "/var/gemini/vhosts/${SERVER_NAME}" 2>/dev/null || cd "/var/gemini/sites/default"
   export SCRIPT_RELATIVE_FILENAME="$(printf "%s\n" "$SCRIPT_NAME" | cut -d/ -f2-)"
 fi

 export DOCUMENT_ROOT="$(pwd | sed 's|///*|/|g')"

 exec supersu "$(id -u "${DROP_TO}")" "$(id -g "${DROP_TO}")" "$(id -g "${DROP_TO}")" "$0" stage2

 elif [ "$1" = "stage2" ];then

 ### TODO: if I'm going to guess file extensions I need to take those into account.

 trailing_slash="$(printf "%s\n" "$SCRIPT_RELATIVE_FILENAME" | rev | cut -b1 | tr -cd '/')"
 if [ "$(path_info_find "${DOCUMENT_ROOT}/${SCRIPT_RELATIVE_FILENAME}")" ];then
   export PATH_INFO="$(path_info_find "${DOCUMENT_ROOT}/${SCRIPT_RELATIVE_FILENAME}" | tail -n1)"
   export SCRIPT_FILENAME="$(normalpath "/$(path_info_find "${DOCUMENT_ROOT}/${SCRIPT_RELATIVE_FILENAME}" | head -n1)")${trailing_slash}"
 else
   export PATH_INFO=""
   export SCRIPT_FILENAME="$(normalpath "/${DOCUMENT_ROOT}/${SCRIPT_RELATIVE_FILENAME}")${trailing_slash}"
 fi


 #  SCRIPT_FILENAME="$(normalpath "/${DOCUMENT_ROOT}/$SCRIPT_FILENAME")"
 if ! printf "%s\n" "${SCRIPT_FILENAME}" | grep "^${DOCUMENT_ROOT}" >/dev/null 2>&1;then
   printf '59 BAD REQUEST (guru meditation: 2) "%s" not in "%s"\r\n' "${SCRIPT_FILENAME}" "${DOCUMENT_ROOT}"
   exit 1
 fi

 ### response code then mime-type
 ### why is script_name and path separate?

 ### this needs to have the PATH_INFO stripped off. but it isn't used in geminid anyway, so fuck it for now.
 export QUERY_STRING="$(printf "%s\n" "$REQUEST_URI" | uricut -q)"


 export SCRIPT_FILENAME

 #printf "20 text/plain\r\n"
 #env

 if [ -e "$SCRIPT_FILENAME" ];then #this will likely be always true because of how path info finder works.
   CONTENT_TYPE="$(mime-type "$SCRIPT_FILENAME")"
   case "$CONTENT_TYPE" in
     inode/directory)
      if [ ! "$PATH_INFO" ];then
        if ! printf "%s\n" "$SCRIPT_NAME" | grep '/$' 2>&1 >/dev/null;then
          printf "31 %s/\r\n" "$SCRIPT_NAME" ### SCRIPT_NAME should not be used this way.
          exit 0
        fi
      fi
      if [ -f $SCRIPT_FILENAME/.redirect ];then
        printf "30 %s\r\n" "$(cat "$SCRIPT_FILENAME/.redirect")"
        exit 0
      fi
      if [ -x "$SCRIPT_FILENAME/index.cgi" ];then
        # we don't need to come back from here.
        cd "$SCRIPT_FILENAME"
        exec "$SCRIPT_FILENAME/index.cgi" | sed 's/\([^\r]\)$/\1\r/g' #only put the \r if it doesn't happen already
        exit 0
      fi
      if [ -f "${SCRIPT_FILENAME}/index.php" ];then
        cd "${SCRIPT_FILENAME}"
        exec php "${SCRIPT_FILENAME}/index.php"
        exit 0
      fi

     # printf "%s\n%s\n" "$REQUEST_DOMAIN" "$SSL_TLS_SNI"
     # printf "SCRIPT_FILENAME: %s\n" "$SCRIPT_FILENAME"

      if [ -f "$SCRIPT_FILENAME/index.gmi" ];then
        if [ "$PATH_INFO" ];then
          printf "51 PATH_INFO is set, but we didn't find a CGI to pass it to.\r\n"
          exit 1
        fi
        printf "20 text/gemini\r\n"
        cat "$SCRIPT_FILENAME/index.gmi" | sed 's/\([^\r]\)$/\1\r/g'
        exit 0
      fi
      if [ -f "$SCRIPT_FILENAME/index.♊︎" ];then
        if [ "$PATH_INFO" ];then
          printf "51 PATH_INFO is set, but we didn't find a CGI to pass it to.\r\n"
          exit 1
        fi
        printf "20 text/gemini\r\n"
        cat "$SCRIPT_FILENAME/index.♊︎" | sed 's/\([^\r]\)$/\1\r/g'
        exit 0
      fi
      printf "20 text/gemini\r\n"
      #if [ -f "$SCRIPT_FILENAME/.autogen" ];then #why did I require this to be a thing?
      printf "## autogenerated list of stuff in %s\r\n" "$SCRIPT_NAME"
      printf "=> ..\r\n"
      if [ "$user" ];then
        find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type d -print0 | xargs -r0 basename -zas .gmi | xargs -r0 printf "=> %s#dir\r\n" | tail -n+2 #skip self
        find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type f -print0 | xargs -r0 basename -zas .gmi | xargs -r0 printf "=> %s#file\r\n"
        find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type l -print0 | xargs -r0 basename -zas .gmi | xargs -r0 printf "=> %s#link\r\n"

 #         find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type f | cut -d/ -f5- | grep . | cut -d. -f1 | tr '\n' '\0' | xargs -r0 printf "=> /~${user}/%s#file\r\n"
 #         find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type l | cut -d/ -f5- | grep . | cut -d. -f1 | tr '\n' '\0' | xargs -r0 printf "=> /~${user}/%s#link\r\n"
      else
        find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type d | cut -d/ -f6- | grep . | cut -d. -f1 | tr '\n' '\0' | xargs -r0 printf '=> /%s#dir\r\n' | tail -n+2 #skip self
        find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type f | cut -d/ -f6- | grep . | cut -d. -f1 | tr '\n' '\0' | xargs -r0 printf '=> /%s#file\r\n'
        find -H "$SCRIPT_FILENAME" -not -path '*/\.*' -maxdepth 1 -type l | cut -d/ -f6- | grep . | cut -d. -f1 | tr '\n' '\0' | xargs -r0 printf '=> /%s#link\r\n'
      fi
      exit 0
      #fi
      #printf '51 %s Not Found I guess\r\n' "$SCRIPT_FILENAME"
      #logger -t geminid 'not found: '"$REQUEST_URI"
 #     printf "wtf, george?\r\n"
 #     env
      ;;
    *)
      extension="$(rev <<< "${SCRIPT_FILENAME}" | cut -d. -f1 | rev)"
      if [ "$extension" = "php" ];then #lol. who needs +x anyway? :D
        cd "$(dirname "$SCRIPT_FILENAME")"
        exec php "${SCRIPT_FILENAME}"
        exit 0
      fi
      if [ -x "$SCRIPT_FILENAME" ];then
        cd "$(dirname "$SCRIPT_FILENAME")"
        exec "$SCRIPT_FILENAME"
        exit 0
      else
        if [ "$PATH_INFO" ];then
          printf "51 PATH_INFO is set, but we didn't find a CGI to pass it to.\r\n"
          exit 1
        fi
        printf "20 %s\r\n" "$CONTENT_TYPE"
        cat -- "$SCRIPT_FILENAME"
      fi
      ;;
   esac
 else
   logger -t geminid "HOW ARE WE GETTING HERE?!?"
   if [ -x "$SCRIPT_FILENAME.cgi" ];then
     if [ "$user" ];then
       printf "47 CGIs for users not implemented yet\r\n" # wat?
     else
       cd "$(dirname "$SCRIPT_FILENAME")"
       exec "$SCRIPT_FILENAME.cgi"
     fi
   fi
   if [ -e "$SCRIPT_FILENAME.php" ];then
     cd "$(dirname "${SCRIPT_FILENAME}")"
     exec php "${SCRIPT_FILENAME}.php"
   fi
   if [ -e "${SCRIPT_FILENAME}.♊︎" ];then
     if [ "$PATH_INFO" ];then
       printf "51 PATH_INFO is set, but we didn't find a CGI to pass it to.\r\n"
       exit 1
     fi
     printf "20 text/gemini\r\n"
        printf "# TESTING 1\r\n"
     cat "${SCRIPT_FILENAME}.♊︎" | sed 's/\([^\r]\)$/\1\r/g'

     exit 1
   fi
   if [ -e "${SCRIPT_FILENAME}.gmi" ];then
     if [ "$PATH_INFO" ];then
       printf "51 PATH_INFO is set, but we didn't find a CGI to pass it to.\r\n"
       exit 1
     fi
     printf "20 text/gemini\r\n"
        printf "# TESTING 2\r\n"
     cat "${SCRIPT_FILENAME}.gmi" | sed 's/\([^\r]\)$/\1\r/g'

     exit 1
   fi
   if [ -x "${DOCUMENT_ROOT}/.rewrite" ];then
     "${DOCUMENT_ROOT}/.rewrite"
   else
     printf "20 text/plain\r\nI don't know what you mean. %s\r\n" "$SCRIPT_FILENAME"
     printf "%s\n" "$(date)"
     env | sort
   fi
 fi
 fi