Small but complete Minus server

implemented as a BASH script

This fully complies with the Minus Protocol Specification.

Save this as mserver and mark it executable with chmod or your GUI file manager. This requires mini-inetd, which you will probably find in a package called Tcputils. This package also includes tcpconnect which is mentioned below.

Start mserver with mserver start and stop it with mserver stop.

You are encouraged to edit the values of indexfile and requestlog. If you do not, a new directory will be created in ${HOME} called minus-contents. You can edit your index file and your pages with an ordinary text editor.

To experiment with your new server (before you start serving it as a Tor Onion Service) you can use tcpconnect. printf "" | tcpconnect -r -v 127.0.0.1 1990 will get your index.minus page. This is like the index.html page in HTTP. It should contain the URLs of your other pages and files.

The printf command sends the specifier to the server. In the example above, a zero-length specifier is sent, so, in accordance with the Minus specification, the specifier defaults to index.minus.

Please read the comments in mserver. Comments to this post are welcome.

#!/bin/bash

# mserver 1.0
# Copyright (C) 2022 the author indicated below
# The author of mserver made an OpenPGP,
# RSA key pair. The fingerprint of this key pair is
# BA34F30AC917CB0714884A3DA6BDBF5757B731E9
# mserver is distributed under the terms of the GNU General
# Public License, version 3 (https://www.gnu.org/licenses/gpl.html).
# mserver is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY--without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# Only the path name in indexfile determines the file served. No part of user input is used as
# part of the path name of the file. This is much more secure than determining the path name directly from
# user input. A file can not be served simply because it is in a certain directory. Only listing the file in
# indexfile makes it available. Specifiers need not contain any part of the path names of the files they
# specify.

# Each line of indexfile is

# <specifier>|<path name of file>

# specifier may not contain any characters except "0123456789abcdefghijklmonpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-/_"
# because all other characters are removed from theinput.

# Path names that do not begin with / are relative to the directory of indexfile.

thisfile="$(readlink -e "${0}")"

if test "${1}" = "start"
then
  if test -z "$(ps -o args -C mini-inetd | grep -F "${thisfile}")"
  then
    mini-inetd 127.0.0.1:1990 "${thisfile}" & # start serving
  fi
  exit 0
elif test "${1}" = "stop"
then
  theID="$(ps -o pid,args -C mini-inetd | grep -F "${thisfile}" | sed "s/^[ \t]*//" | grep -o "^[0-9]*")"
  if test -n "${theID}"
  then
    kill ${theID} # stop serving
  fi
  exit 0
fi

# mini-inetd listens for tcp connections on port 1990.
# For each connection, this file is started with standard input and standard output connected to the socket.
# When this file exits, the tcp connection is closed.

if test "$(ps -o args -C "$(basename "${thisfile}")" | grep -cF "${thisfile}")" -gt 12 # mitigate DoS attacks
then
  exit 0
fi

read -t 30 -n 255 theinput # Read 1 line, but no more than 255 bytes. Timeout after 30 seconds to mitigate DoS attacks.
theinput="$(printf "%s" "${theinput}" | tr -dc "0-9A-Za-z\.\-/_" | sed "s/^\///")" # remove anything not allowed and initial /

# set indexfile and requestlog to desired values
indexfile="${HOME}/minus-contents/minus.index"
requestlog="/dev/null" # this can be /dev/null to prevent logging

indexdir="$(dirname "${indexfile}")"

if ! test -f "${indexfile}" # no index file
then
  mkdir -p "${indexdir}"
  printf "%s\n%s" "index.minus|index.minus" "other.minus|other.minus" > "${indexfile}"
  printf "%s\n" "This is the home or index page." > "${indexdir}/index.minus"
  printf "%s\n" "This is the other page." > "${indexdir}/other.minus"
fi

cd "${indexdir}"

if test -z "${theinput}" # if no input, default to index.minus
then
  theinput="index.minus" # This is the home or index page. It should have links to the other pages.
fi

if test -n "$(grep -m 1 -o "^${theinput}|" "${indexfile}" | grep -F "${theinput}|")" # necessary because theinput may contain .
then
  thefile="$(grep -m 1 "^${theinput}|" "${indexfile}" | sed "s/^[^|]*|//")" # use indexfile to find path name of the file
else
  thefile=""
fi

if test -n "${thefile}"
then
  cat "${thefile}" # return the file
  printf "%s sent %s\n" "$(date "+%Y-%m-%d %I:%M:%S %p")" "${theinput}" >> "${requestlog}"
else
  printf "\"%s\" does not specify a file that this server will serve.\nTry \"index.minus\".\n" "${theinput}" # return an error
  printf "%s miss %s\n" "$(date "+%Y-%m-%d %I:%M:%S %p")" "${theinput}" >> "${requestlog}"
fi

exit 0

#internet #protocol #tcp #file-server #hypertext #minus #minus-protocol

There are no comments yet.