about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--README.md3
-rwxr-xr-xbin/connusers.py21
-rwxr-xr-xbin/institute.sh45
-rwxr-xr-xbin/makeuser83
-rwxr-xr-xbin/motdrotate.py41
-rw-r--r--bin/newmail.sh12
-rwxr-xr-xbin/regusers.py23
-rwxr-xr-xbin/rmuser12
-rwxr-xr-xbin/toot.py70
-rwxr-xr-xbin/weekconns.py18
-rw-r--r--misc/email.tmpl7
-rw-r--r--misc/motd.txt42
-rw-r--r--misc/pkglist.txt112
-rw-r--r--misc/toot.json.template6
15 files changed, 499 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b3cdfcf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+misc/toot.json
+fuzzies.log
+users-added.log
+newusers.dat
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7245bc5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# tilde.institute-backend
+
+Scripts that make tilde.institute work
diff --git a/bin/connusers.py b/bin/connusers.py
new file mode 100755
index 0000000..a09ae4a
--- /dev/null
+++ b/bin/connusers.py
@@ -0,0 +1,21 @@
+#!/usr/local/bin/python3 -I
+
+from sys import exit
+import subprocess
+
+def checkconns():
+    try:
+        conntable = open("/var/www/htdocs/table.connusers", "w")
+    except:
+        print("Can't access connected user table. Who are you?")
+        exit(0)
+
+    connusers = list(set(subprocess.check_output("/usr/bin/who -q; exit 0", stderr=subprocess.STDOUT,shell=True).decode().splitlines()[0].split()))
+    conntable.write("<ul>\n")
+    for conn in connusers:
+        conntable.write("<li><a href=\"https://"+ conn +".tilde.institute\">"+ conn +"</a></li>\n")
+
+    conntable.write("</ul>\n")
+
+if __name__ == '__main__':
+    checkconns()
diff --git a/bin/institute.sh b/bin/institute.sh
new file mode 100755
index 0000000..b051922
--- /dev/null
+++ b/bin/institute.sh
@@ -0,0 +1,45 @@
+#!/usr/local/bin/bash
+####################################################
+#
+# This is the bash script used to automagically check for new submitted users
+# and add them to the Tilde Institute system.
+# It is intended to be run as a cron job every few minutes, or however long.
+#
+####################################################
+#
+#    Copyright (c) 2018 Ben Morrison, also known as "ahriman". All rights reserved.
+#    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+#     1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+#     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+#     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+#     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+####################################################
+
+#	First we check if new users have been submitted by the PHP script on the site
+#	If no users have been submitted, do nothing.
+#	If they have been submitted, begin by moving the newusers.csv file to a new location
+if [[ -f /var/www/htdocs/newusers.csv ]] ; then
+	mv /var/www/htdocs/newusers.csv /var/www/newusers.csv
+	touch /var/www/htdocs/newusers.csv
+    chmod 666 /var/www/htdocs/newusers.csv
+#	assign the file to a variable to make it easier to work with
+	newusers="/var/www/newusers.csv"
+#	now read the file line by line and chop it up by field
+	while IFS=: read -r f1
+	do
+#	Call the makeuser script I borrowed from Ben Harris of tilde.team
+#	and modified for my own use
+        echo $f1 >> /home/ahriman/users-to-add
+#		exec '/home/ahriman/bin/makeuser $f1'
+	done <"$newusers"
+
+#	append list of new users created this run for later review
+#	then delete the csv file
+	cat /var/www/newusers.csv >> /var/www/logs/newusers.log
+	rm -f /var/www/newusers.csv
+
+#	reload the httpd config
+#	httpdpid=`pgrep httpd | awk 'NR==1{print $1}'`
+#	kill -HUP $httpdpid
+fi
diff --git a/bin/makeuser b/bin/makeuser
new file mode 100755
index 0000000..c996d6f
--- /dev/null
+++ b/bin/makeuser
@@ -0,0 +1,83 @@
+#!/usr/local/bin/bash
+# ---------------------------------------------------------------------------
+# makeuser - tilde.institute new user creation
+# Usage: makeuser [-h|--help] <username> <email> "<pubkey>"
+# Based on the tilde.team makeuser script, with some modifications
+# ---------------------------------------------------------------------------
+
+PROGNAME=${0##*/}
+VERSION="0.1"
+
+error_exit() {
+  echo -e "${PROGNAME}: ${1:-"Unknown Error"}" >&2
+  exit 1
+}
+
+usage() {
+  echo -e "usage: $PROGNAME [-h|--help] <username> <email> \"<pubkey>\""
+}
+
+[[ $(id -u) != 0 ]] && error_exit "you must be the superuser to run this script."
+
+case $1 in
+  -h | --help)
+    usage; exit ;;
+  -* | --*)
+    usage; error_exit "unknown option $1" ;;
+  *)
+    [[ $# -ne 3 ]] && error_exit "not enough args"
+
+# generate a random 20 digit password
+# encrypt the password and pass it to
+# useradd, set ksh as default shell
+    echo "adding new user $1"
+    newpw=$(pwgen -1B 20)
+    pwcrypt=$(encrypt ${newpw})
+    useradd -m -g 1001 -p $pwcrypt -s /bin/ksh -k /etc/skel $1
+
+# make the public_html directory for the users
+	mkdir /var/www/users/$1
+	chown $1:tilde /var/www/users/$1
+	ln -s /var/www/users/$1 /home/$1/public_html
+
+# set up the httpd configuration for
+# individual users. this config forces tls
+# for all subdomains
+    echo "server \"$1.tilde.institute\" {
+        listen on \$ext_addr port 80 block return 301 \"https://\$SERVER_NAME\$REQUEST_URI\"
+    }
+    server \"$1.tilde.institute\" {
+		listen on \$ext_addr tls port 443
+		root \"/users/$1\"
+        tls {
+            key \"/etc/letsencrypt/live/tilde.institute-0001/privkey.pem\"
+            certificate \"/etc/letsencrypt/live/tilde.institute-0001/fullchain.pem\"
+        }
+		directory index index.html
+		directory auto index
+		location \"/*.cgi\" {
+			fastcgi
+		}
+		location \"/*.php\" {
+			fastcgi socket \"/run/php-fpm.sock\"
+		}
+	}" > /etc/httpd/$1.conf
+
+# add the user's vhost config to
+# the main httpd config then gracefully
+# reload the httpd config
+	echo "include \"/etc/httpd/$1.conf\"" >> /etc/httpd-vusers.conf
+    httpdpid=`pgrep httpd | awk 'NR==1{print $1}'`
+    kill -HUP $httpdpid
+
+# send welcome email
+        sed -e "s/newusername/$1/g" /admin/misc/email.tmpl | doas -u admins mail -s "welcome to tilde.institute!" $2
+
+# subscribe to mailing list
+    echo " " | doas -u $1 mail -s "subscribe" institute-join@lists.tildeverse.org
+
+# announce the new user's creation on mastodon
+# then copy their ssh key to their home directory
+    /admin/bin/toot.py "Welcome new user ~$1!"
+    echo "$3" | tee /home/$1/.ssh/authorized_keys
+esac
diff --git a/bin/motdrotate.py b/bin/motdrotate.py
new file mode 100755
index 0000000..ceb8147
--- /dev/null
+++ b/bin/motdrotate.py
@@ -0,0 +1,41 @@
+#!/usr/local/bin/python3
+
+import sys
+import random
+
+##############################################
+## Uses a skeleton motd plus a random quote ##
+## to produce a motd with a nifty quote.    ##
+##------------------------------------------##
+## Created by ahriman - ahriman@falte.red   ##
+## --> BSD 3-clause license applies         ##
+##############################################
+
+def pullfile(filename):
+    with open(filename, 'r') as filesrc:
+        filedata = filesrc.read()
+        return filedata
+
+def rotatemotd(motd):
+    motdmsgs = ['Abandon hope all ye who enter here',
+            '"In matters of life and death there is no cheating; there is only living and dying"',
+            '"New technology is not good or evil in and of itself. It\'s all about how people choose to use it."',
+            '"Technology is, of course, a double-edged sword. Fire can cook our food but also burn us."',
+            '"If we lose love and self-respect for each other, this is how we finally die."',
+            '"We live in a society exquisitely dependent on science and technology, in which hardly anyone knows anything about science and technology."',
+            '"Any sufficiently advanced technology is indistinguishable from magic."']
+    motdchoice = random.choice(motdmsgs)
+    try:
+        with open("/etc/motd", "w") as etcmotd:
+            etcmotd.write(motd)
+            etcmotd.write(motdchoice)
+            etcmotd.write("\n")
+            etcmotd.write("\n")
+    except:
+        print("Unable to open /etc/motd for writing. Who are you?")
+        sys.exit(0)
+
+if __name__=="__main__":
+    motdskel = pullfile("/admin/misc/motd.txt")
+    rotatemotd(motdskel)
+
diff --git a/bin/newmail.sh b/bin/newmail.sh
new file mode 100644
index 0000000..59e42e2
--- /dev/null
+++ b/bin/newmail.sh
@@ -0,0 +1,12 @@
+#!/usr/local/bin/bash
+
+NewMail(){
+    NEWMAIL=$(mailx &)
+    UNREAD=$(echo $NEWMAIL |grep -o 'messages.*new' | cut -f2 -d" ")
+}
+NewMail # call NewMail function
+UNREAD=${UNREAD/>/}
+
+if [ -n "$UNREAD" ]; then
+    echo "`whoami` you have $UNREAD new mail(s) "
+fi
diff --git a/bin/regusers.py b/bin/regusers.py
new file mode 100755
index 0000000..758da18
--- /dev/null
+++ b/bin/regusers.py
@@ -0,0 +1,23 @@
+#!/usr/local/bin/python3
+
+import os
+import sys
+
+def get_regusers(a_dir):
+    return [name for name in os.listdir(a_dir)
+            if os.path.isdir(os.path.join(a_dir, name))]
+
+if __name__ == "__main__":
+
+    try:
+        usertable = open("/var/www/htdocs/table.regusers", "w")
+    except:
+        print("Can't access registered user table. Are you root?")
+        sys.exit(0)
+
+    regusers = get_regusers("/home")
+    usertable.write("<ul>\n")
+    for user in sorted(regusers):
+        if user != ".git" and user != "ahriman" and user != "uucp" and user != "admins":
+            usertable.write("<li><a href=\"https://"+ user +".tilde.institute\">"+ user +"</a></li>\n")
+    usertable.write("</ul>\n")
diff --git a/bin/rmuser b/bin/rmuser
new file mode 100755
index 0000000..b220181
--- /dev/null
+++ b/bin/rmuser
@@ -0,0 +1,12 @@
+#!/usr/local/bin/bash
+
+echo "Removing user $1 from the system"
+userdel $1
+echo "Cleaning /home and /var/www/users"
+rm -rf /home/$1
+rm -rf /var/www/users/$1
+echo "Removing httpd config"
+rm -f /etc/httpd/$1.conf
+httpdpid=`pgrep httpd | awk 'NR==1{print $1}'`
+kill -HUP $httpdpid
+echo "Done! Don't forget to remove the appropriate include line from httpd-vusers.conf"
diff --git a/bin/toot.py b/bin/toot.py
new file mode 100755
index 0000000..79c8d81
--- /dev/null
+++ b/bin/toot.py
@@ -0,0 +1,70 @@
+#!/usr/local/bin/python2
+
+# Borrowed from Ben Harris of tilde.team
+# Thanks Ben!
+
+import json
+import os
+import sys
+
+import click
+import emoji
+from mastodon import Mastodon
+
+# get config
+path = os.getenv('TOOT_JSON_PATH', os.path.dirname(os.path.abspath(__file__)))
+config_file = os.path.join(path, '../misc/toot.json')
+with open(config_file) as f:
+    config = json.load(f)
+
+# set up connection to mastodon
+mastodon = Mastodon(
+    client_id=config['client_id'],
+    client_secret=config['client_secret'],
+    access_token=config['access_token'],
+    api_base_url=config['base_url'],
+)
+
+def check_valid_files(ctx, param, filenames):
+    if filenames:
+        if len(filenames) > 4:
+            raise click.BadParameter('too many files!')
+        for filename in filenames:
+            if not os.path.isfile(filename):
+                raise click.BadParameter('"{}" is not a valid file'.format(filename))
+    return filenames
+
+def post_to_masto(status, media):
+    files = []
+    for fname in media:
+        media_info = mastodon.media_post(fname)
+        files.append(media_info)
+    if not files:
+        files = None
+    mastodon.status_post(status, media_ids=files)
+
+
+@click.command()
+@click.argument('status', required=False)
+@click.option('--media', '-m', multiple=True, callback=check_valid_files)
+def toot(status, media):
+    # get status from argument or from stdin
+    if not status:
+        status = "".join(sys.stdin).strip()
+
+    # replace shortcodes with emoji :thumbsup:
+    status = emoji.emojize(status, use_aliases=True)
+
+    # check status length and post status
+    if len(status) > 500:
+        print("Status is too long, try again")
+    elif len(status) == 0:
+        print("Did you type a status?")
+    else:
+        post_to_masto(status, media)
+
+
+
+if __name__=='__main__':
+    toot()
+
diff --git a/bin/weekconns.py b/bin/weekconns.py
new file mode 100755
index 0000000..fb152e6
--- /dev/null
+++ b/bin/weekconns.py
@@ -0,0 +1,18 @@
+#!/usr/local/bin/python3 -I
+
+from sys import exit
+import subprocess
+
+def weekconns():
+    try:
+        conntable = open("/var/www/htdocs/table.weekconns", "w")
+    except:
+        print("Can't access connected user table. Who are you?")
+        exit(0)
+
+    weekconns = list(set(subprocess.check_output("last | grep tty | awk '{print $1}'; exit 0", stderr=subprocess.STDOUT,shell=True).decode().strip()))
+    conntable.write(str(len(weekconns)))
+    conntable.close()
+
+if __name__ == '__main__':
+    weekconns()
diff --git a/misc/email.tmpl b/misc/email.tmpl
new file mode 100644
index 0000000..5e09f24
--- /dev/null
+++ b/misc/email.tmpl
@@ -0,0 +1,7 @@
+Hello newusername,
+
+Your account has been activated at tilde.institute! If you have any questions, 
+please feel free to email the sysadmins at admins@tilde.institute
+
+Regards,
+the tilde.institute team
diff --git a/misc/motd.txt b/misc/motd.txt
new file mode 100644
index 0000000..b2b4059
--- /dev/null
+++ b/misc/motd.txt
@@ -0,0 +1,42 @@
+OpenBSD 6.4 (GENERIC.MP) #1: Mon Nov 26 10:18:14 CET 2018
+
+Welcome to the Tilde Institute!
+Please read the Code of Conduct on our web site before continuing.
+
+Mail clients available: mutt neomutt alpine
+
+Learned something cool today? Add it to the wiki!
+https://tilde.institute/wiki
+
+Common commands:
+chat            - Join us on IRC!
+tmux / screen   - Terminal multiplexer / session management
+chsh            - Change your interactive shell
+
+Games:
+holodeck        - Collaborative world-building!
+botany          - Plant a little garden!
+tron            - Play with other ~institute members!
+nethack         - The classic roguelike!
+angband         - Roguelike set in Middle-Earth
+zork            - The classic adventure game
+dcss            - Dungeon Crawl Stone Soup!
+                   (Connects to https://crawl.tildeverse.org)
+asciifarm       - Multi-user persistent social-farming game
+
+NEW!! Tildeverse Dungeon Crawl Stone Soup server!
+        Webtiles: https://crawl.tildeverse.org
+        ASCII: Run the command 'dcss'
+
+MUD Clients: tintin++ tinyfugue
+
+Latency issues? Use 'mosh' instead of 'ssh'
+Make sure your home PC's LANG and LC_CTYPE vars are set
+to a UTF-8 locale before connecting via mosh
+
+motd        - Repeat this message
+
+Please contact ahriman with any issues or questions.
+Available on chat in #institute
+or at ahriman@tilde.institute
+
diff --git a/misc/pkglist.txt b/misc/pkglist.txt
new file mode 100644
index 0000000..fcbb2f2
--- /dev/null
+++ b/misc/pkglist.txt
@@ -0,0 +1,112 @@
+alpine-2.21p0       UW e-mail client
+angband-3.3.2p2-no_x11 rogue-like game
+asciidoc-8.6.9p1    text document format for writing documents and man pages
+autoconf-2.69p2     automatically configure source code on many Un*x platforms
+automake-1.16.1     GNU Standards-compliant Makefile generator
+autossh-1.4f        SSH monitoring
+bash-4.4.23         GNU Bourne Again Shell
+cmake-3.10.2p0v0    portable build system
+colorls-6.3         ls(1) that can use color to display file attributes
+coreutils-8.30      file, shell and text manipulation utilities
+cowsay-3.03p0       speaking ascii cow
+dash-0.5.10.2       Debian Almquist shell, POSIX-compliant
+dungeon-2.7sp0      text adventure game
+elvish-0.12         cross-platform, friendly, and expressive shell
+emacs-26.1p2-no_x11 GNU editor: extensible, customizable, self-documenting
+figlet-2.2.5        generates ASCII banner art
+fish-2.7.1p0        friendly interactive shell
+gcc-4.9.4p12        GNU compiler collection: core C compiler
+ghc-8.2.2p2         compiler for the functional language Haskell
+git-2.19.1          GIT - Tree History Storage Tool
+gmake-4.2.1         GNU make
+gnupg-2.2.10        GNU privacy guard - a free PGP replacement
+go-1.11             Go programming language
+gophernicus-2.5p0   modern gopher server
+inotify-tools-3.14pl0 programs providing a simple interface to inotify
+intel-firmware-20180807p0v0 microcode update binaries for Intel CPUs
+ircII-20170704p1    Internet Relay Chat client
+irssi-1.1.1p0       modular IRC client with many features (ipv6,socks,proxy)
+joe-4.6             Joe's Own Editor
+kcgi-0.10.7         minimal CGI library for web applications
+ksql-0.3.2          yet another SQLite wrapper
+kwebapp-0.5.6       web application source generator
+libident-0.32p1     library to interface the ident protocol server (rfc1413)
+links-1.03p0        text browser, displays while downloading
+lowdown-0.4.1       simple markdown translator
+lynx-2.8.9rel1      text web browser
+mariadb-server-10.0.36p0v1 multithreaded SQL database (server)
+mercurial-4.5.3p1   fast, lightweight source control management
+mongodb-3.2.13p2    scalable, high-performance document-oriented database
+mosh-1.3.2p1        mobile shell
+mutt-1.10.1v3-gpgme-sasl tty-based e-mail client
+nano-3.1            Pico editor clone with enhancements
+nasm-2.13.03        general-purpose multi-platform x86 assembler
+ncdu-1.13           ncurses-based du(1)
+neomutt-20180716-gpgme-sasl tty-based e-mail client, Mutt with patches
+nethack-3.6.0p0-no_x11 dungeon explorin', hackin', game.  Piece of cake
+node-8.12.0         V8 JavaScript for clients and servers
+password-store-1.7.3 simple password store
+pear-1.10.1p0       base classes for common PHP tasks
+php-7.0.32p1        server-side HTML-embedded scripting language
+php-7.2.10          server-side HTML-embedded scripting language
+php-awl-0.59        Andrews web libraries for PHP
+php-bz2-7.0.32p1    bzip2 compression extensions for php
+php-cgi-7.0.32p1    php CGI binary
+php-curl-7.0.32p1   curl URL library extensions for php
+php-dba-7.0.32p1    dba GDBM access extensions for php
+php-dbg-7.0.32p1    interactive php debugger
+php-gmp-7.0.32p1    gmp math library support for php
+php-imap-7.0.32p1   imap, pop3 and nntp extensions for php
+php-intl-7.0.32p1   intl library support for php
+php-ldap-7.0.32p1   ldap protocol extensions for php
+php-librdf-1.0.17.1p2 Redland librdf PHP Bindings
+php-markdown-1.6.0p0 Markdown implementation for PHP
+php-mcrypt-7.0.32p1 mcrypt encryption/decryption extensions for php
+php-mysql-5.6.38    mysql database access extensions for php5
+php-mysqli-7.0.32p1 mysql database access extensions for php
+php-mysqli-7.2.10   mysql database access extensions for php
+php-odbc-7.0.32p1   odbc database access extensions for php
+php-openid-2.1.2p7  OpenID authentication for PHP
+php-pcntl-7.0.32p1  PCNTL extensions for php
+php-pdo_mysql-7.0.32p1 PDO mysql database access extensions for php
+php-pgsql-7.0.32p1  pgsql database access extensions for php
+php-pspell-7.0.32p1 pspell library extensions for php
+php-shmop-7.0.32p1  shared memory extensions for php
+php-snmp-7.0.32p1   snmp protocol extensions for php
+php-soap-7.0.32p1   SOAP functions for php
+php-sqlite3-7.0.32p1 sqlite3 database access extension for php
+php-tidy-7.0.32p1   tidy HTML cleaner bindings
+php-xmlrpc-7.0.32p1 XML RPC functions for php
+php-xsl-7.0.32p1    XSL functions for php
+php-zip-7.0.32p1    zip functions for php
+pico-5.09           UW text editor
+portslist-6.8       full list of pkgpaths in ports
+pwgen-2.08          simple password generator
+py-pip-9.0.3        Python easy_install replacement
+py3-click-6.7       command line library for Python
+py3-click-log-0.3.2 logging integration for Python click
+py3-click-plugins-1.0.2 register CLI commands via setuptools entry-points
+py3-click-threading-0.4.3 multithreading in Python click
+py3-pip-9.0.3       Python easy_install replacement
+quirks-3.16         exceptions to pkg_add rules
+ranger-1.9.2        minimalistic console file manager
+rlwrap-0.43         generic readline wrapper for various programs
+ruby-2.5.1          object oriented script language with threads
+rust-1.29.2         compiler for Rust Language
+screen-4.0.3p6      multi-screen window manager
+sl-5.02             Steam Locomotive
+stow-2.2.2          manages software package installations with symlinks
+subversion-1.10.2   subversion revision control system
+tcsh-6.20.00p1      extended C-shell with many useful features
+tintin-2.01.3       client program for playing muds with advanced features
+tinyfugue-4.0s1p4   programmable MUD client, with macro support and more
+ttyrec-1.0.8p3      tty recorder
+unzip-6.0p11        extract, list & test files in a ZIP archive
+uucp-1.07p4         UUCP suite
+uucpd-1.0           UUCP inetd program
+vim-8.1.0438-no_x11 vi clone, many additional features
+weechat-2.2         fast, light and extensible chat client
+wget-1.19.5         retrieve files from the web via HTTP, HTTPS and FTP
+yasm-1.3.0p1        complete rewrite of the NASM assembler
+ytalk-3.1.1p3-no_x11 enhanced talk that allows for multiple parties
+zsh-5.6.2           Z shell, Bourne shell-compatible
diff --git a/misc/toot.json.template b/misc/toot.json.template
new file mode 100644
index 0000000..1bffc99
--- /dev/null
+++ b/misc/toot.json.template
@@ -0,0 +1,6 @@
+{
+    "client_id": "tilde.institute@protonmail.com",
+    "client_secret": "",
+    "access_token": "",
+    "base_url": "https://tilde.zone"
+}